srfi-13.c 92 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368
  1. /* Copyright 2001,2004-2006,2008-2013,2017-2019
  2. Free Software Foundation, Inc.
  3. This file is part of Guile.
  4. Guile is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Lesser General Public License as published
  6. by the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. Guile is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  11. License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with Guile. If not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #ifdef HAVE_CONFIG_H
  16. # include <config.h>
  17. #endif
  18. #include <string.h>
  19. #include <unicase.h>
  20. #include <unictype.h>
  21. #include "deprecation.h"
  22. #include "error.h"
  23. #include "eval.h"
  24. #include "gsubr.h"
  25. #include "hash.h"
  26. #include "list.h"
  27. #include "numbers.h"
  28. #include "pairs.h"
  29. #include "procs.h"
  30. #include "srfi-14.h"
  31. #include "symbols.h"
  32. #include "srfi-13.h"
  33. #define MY_VALIDATE_SUBSTRING_SPEC(pos_str, str, \
  34. pos_start, start, c_start, \
  35. pos_end, end, c_end) \
  36. do { \
  37. SCM_VALIDATE_STRING (pos_str, str); \
  38. scm_i_get_substring_spec (scm_i_string_length (str), \
  39. start, &c_start, end, &c_end); \
  40. } while (0)
  41. #define MY_SUBF_VALIDATE_SUBSTRING_SPEC(fname, pos_str, str, \
  42. pos_start, start, c_start, \
  43. pos_end, end, c_end) \
  44. do { \
  45. SCM_ASSERT_TYPE (scm_is_string (str), str, pos_str, fname, "string"); \
  46. scm_i_get_substring_spec (scm_i_string_length (str), \
  47. start, &c_start, end, &c_end); \
  48. } while (0)
  49. #define REF_IN_CHARSET(s, i, cs) \
  50. (scm_is_true (scm_char_set_contains_p ((cs), scm_c_make_char (scm_i_string_ref (s, i)))))
  51. SCM_DEFINE (scm_string_null_p, "string-null?", 1, 0, 0,
  52. (SCM str),
  53. "Return @code{#t} if @var{str}'s length is zero, and\n"
  54. "@code{#f} otherwise.\n"
  55. "@lisp\n"
  56. "(string-null? \"\") @result{} #t\n"
  57. "y @result{} \"foo\"\n"
  58. "(string-null? y) @result{} #f\n"
  59. "@end lisp")
  60. #define FUNC_NAME s_scm_string_null_p
  61. {
  62. SCM_VALIDATE_STRING (1, str);
  63. return scm_from_bool (scm_i_string_length (str) == 0);
  64. }
  65. #undef FUNC_NAME
  66. #if 0
  67. static void
  68. race_error ()
  69. {
  70. scm_misc_error (NULL, "race condition detected", SCM_EOL);
  71. }
  72. #endif
  73. SCM_DEFINE (scm_string_any, "string-any-c-code", 2, 2, 0,
  74. (SCM char_pred, SCM s, SCM start, SCM end),
  75. "Check if @var{char_pred} is true for any character in string @var{s}.\n"
  76. "\n"
  77. "@var{char_pred} can be a character to check for any equal to that, or\n"
  78. "a character set (@pxref{Character Sets}) to check for any in that set,\n"
  79. "or a predicate procedure to call.\n"
  80. "\n"
  81. "For a procedure, calls @code{(@var{char_pred} c)} are made\n"
  82. "successively on the characters from @var{start} to @var{end}. If\n"
  83. "@var{char_pred} returns true (ie.@: non-@code{#f}), @code{string-any}\n"
  84. "stops and that return value is the return from @code{string-any}. The\n"
  85. "call on the last character (ie.@: at @math{@var{end}-1}), if that\n"
  86. "point is reached, is a tail call.\n"
  87. "\n"
  88. "If there are no characters in @var{s} (ie.@: @var{start} equals\n"
  89. "@var{end}) then the return is @code{#f}.\n")
  90. #define FUNC_NAME s_scm_string_any
  91. {
  92. size_t cstart, cend;
  93. SCM res = SCM_BOOL_F;
  94. MY_VALIDATE_SUBSTRING_SPEC (2, s,
  95. 3, start, cstart,
  96. 4, end, cend);
  97. if (SCM_CHARP (char_pred))
  98. {
  99. size_t i;
  100. for (i = cstart; i < cend; i ++)
  101. if (scm_i_string_ref (s, i) == SCM_CHAR (char_pred))
  102. {
  103. res = SCM_BOOL_T;
  104. break;
  105. }
  106. }
  107. else if (SCM_CHARSETP (char_pred))
  108. {
  109. size_t i;
  110. for (i = cstart; i < cend; i++)
  111. if (REF_IN_CHARSET (s, i, char_pred))
  112. {
  113. res = SCM_BOOL_T;
  114. break;
  115. }
  116. }
  117. else
  118. {
  119. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  120. char_pred, SCM_ARG1, FUNC_NAME);
  121. while (cstart < cend)
  122. {
  123. res = scm_call_1 (char_pred,
  124. scm_c_make_char (scm_i_string_ref (s, cstart)));
  125. if (scm_is_true (res))
  126. break;
  127. cstart++;
  128. }
  129. }
  130. scm_remember_upto_here_1 (s);
  131. return res;
  132. }
  133. #undef FUNC_NAME
  134. SCM_DEFINE (scm_string_every, "string-every-c-code", 2, 2, 0,
  135. (SCM char_pred, SCM s, SCM start, SCM end),
  136. "Check if @var{char_pred} is true for every character in string\n"
  137. "@var{s}.\n"
  138. "\n"
  139. "@var{char_pred} can be a character to check for every character equal\n"
  140. "to that, or a character set (@pxref{Character Sets}) to check for\n"
  141. "every character being in that set, or a predicate procedure to call.\n"
  142. "\n"
  143. "For a procedure, calls @code{(@var{char_pred} c)} are made\n"
  144. "successively on the characters from @var{start} to @var{end}. If\n"
  145. "@var{char_pred} returns @code{#f}, @code{string-every} stops and\n"
  146. "returns @code{#f}. The call on the last character (ie.@: at\n"
  147. "@math{@var{end}-1}), if that point is reached, is a tail call and the\n"
  148. "return from that call is the return from @code{string-every}.\n"
  149. "\n"
  150. "If there are no characters in @var{s} (ie.@: @var{start} equals\n"
  151. "@var{end}) then the return is @code{#t}.\n")
  152. #define FUNC_NAME s_scm_string_every
  153. {
  154. size_t cstart, cend;
  155. SCM res = SCM_BOOL_T;
  156. MY_VALIDATE_SUBSTRING_SPEC (2, s,
  157. 3, start, cstart,
  158. 4, end, cend);
  159. if (SCM_CHARP (char_pred))
  160. {
  161. size_t i;
  162. for (i = cstart; i < cend; i++)
  163. if (scm_i_string_ref (s, i) != SCM_CHAR (char_pred))
  164. {
  165. res = SCM_BOOL_F;
  166. break;
  167. }
  168. }
  169. else if (SCM_CHARSETP (char_pred))
  170. {
  171. size_t i;
  172. for (i = cstart; i < cend; i++)
  173. if (!REF_IN_CHARSET (s, i, char_pred))
  174. {
  175. res = SCM_BOOL_F;
  176. break;
  177. }
  178. }
  179. else
  180. {
  181. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  182. char_pred, SCM_ARG1, FUNC_NAME);
  183. while (cstart < cend)
  184. {
  185. res = scm_call_1 (char_pred,
  186. scm_c_make_char (scm_i_string_ref (s, cstart)));
  187. if (scm_is_false (res))
  188. break;
  189. cstart++;
  190. }
  191. }
  192. scm_remember_upto_here_1 (s);
  193. return res;
  194. }
  195. #undef FUNC_NAME
  196. SCM_DEFINE (scm_string_tabulate, "string-tabulate", 2, 0, 0,
  197. (SCM proc, SCM len),
  198. "@var{proc} is an integer->char procedure. Construct a string\n"
  199. "of size @var{len} by applying @var{proc} to each index to\n"
  200. "produce the corresponding string element. The order in which\n"
  201. "@var{proc} is applied to the indices is not specified.")
  202. #define FUNC_NAME s_scm_string_tabulate
  203. {
  204. size_t clen, i;
  205. SCM res;
  206. SCM ch;
  207. SCM_ASSERT (scm_is_true (scm_procedure_p (proc)),
  208. proc, SCM_ARG1, FUNC_NAME);
  209. SCM_ASSERT_RANGE (2, len, scm_to_int (len) >= 0);
  210. clen = scm_to_size_t (len);
  211. {
  212. /* This function is more complicated than necessary for the sake
  213. of speed. */
  214. scm_t_wchar *buf = scm_malloc (clen * sizeof (scm_t_wchar));
  215. int wide = 0;
  216. i = 0;
  217. while (i < clen)
  218. {
  219. ch = scm_call_1 (proc, scm_from_size_t (i));
  220. if (!SCM_CHARP (ch))
  221. {
  222. SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc));
  223. }
  224. if (SCM_CHAR (ch) > 255)
  225. wide = 1;
  226. buf[i] = SCM_CHAR (ch);
  227. i++;
  228. }
  229. if (wide)
  230. {
  231. scm_t_wchar *wbuf = NULL;
  232. res = scm_i_make_wide_string (clen, &wbuf, 0);
  233. memcpy (wbuf, buf, clen * sizeof (scm_t_wchar));
  234. free (buf);
  235. }
  236. else
  237. {
  238. char *nbuf = NULL;
  239. res = scm_i_make_string (clen, &nbuf, 0);
  240. for (i = 0; i < clen; i ++)
  241. nbuf[i] = (unsigned char) buf[i];
  242. free (buf);
  243. }
  244. }
  245. return res;
  246. }
  247. #undef FUNC_NAME
  248. SCM_DEFINE (scm_substring_to_list, "string->list", 1, 2, 0,
  249. (SCM str, SCM start, SCM end),
  250. "Convert the string @var{str} into a list of characters.")
  251. #define FUNC_NAME s_scm_substring_to_list
  252. {
  253. size_t cstart, cend;
  254. int narrow;
  255. SCM result = SCM_EOL;
  256. MY_VALIDATE_SUBSTRING_SPEC (1, str,
  257. 2, start, cstart,
  258. 3, end, cend);
  259. /* This explicit narrow/wide logic (instead of just using
  260. scm_i_string_ref) is for speed optimizaion. */
  261. narrow = scm_i_is_narrow_string (str);
  262. if (narrow)
  263. {
  264. const char *buf = scm_i_string_chars (str);
  265. while (cstart < cend)
  266. {
  267. cend--;
  268. result = scm_cons (SCM_MAKE_CHAR (buf[cend]), result);
  269. }
  270. }
  271. else
  272. {
  273. const scm_t_wchar *buf = scm_i_string_wide_chars (str);
  274. while (cstart < cend)
  275. {
  276. cend--;
  277. result = scm_cons (SCM_MAKE_CHAR (buf[cend]), result);
  278. }
  279. }
  280. scm_remember_upto_here_1 (str);
  281. return result;
  282. }
  283. #undef FUNC_NAME
  284. /* We export scm_substring_to_list as "string->list" since it is
  285. compatible and more general. This function remains for the benefit
  286. of C code that used it.
  287. */
  288. SCM
  289. scm_string_to_list (SCM str)
  290. {
  291. return scm_substring_to_list (str, SCM_UNDEFINED, SCM_UNDEFINED);
  292. }
  293. SCM_DEFINE (scm_reverse_list_to_string, "reverse-list->string", 1, 0, 0,
  294. (SCM chrs),
  295. "An efficient implementation of @code{(compose list->string\n"
  296. "reverse)}:\n"
  297. "\n"
  298. "@smalllisp\n"
  299. "(reverse-list->string '(#\\a #\\B #\\c)) @result{} \"cBa\"\n"
  300. "@end smalllisp")
  301. #define FUNC_NAME s_scm_reverse_list_to_string
  302. {
  303. SCM result;
  304. long i = scm_ilength (chrs), j;
  305. char *data;
  306. if (i < 0)
  307. SCM_WRONG_TYPE_ARG (1, chrs);
  308. result = scm_i_make_string (i, &data, 0);
  309. {
  310. SCM rest;
  311. rest = chrs;
  312. j = 0;
  313. while (j < i && scm_is_pair (rest))
  314. {
  315. SCM elt = SCM_CAR (rest);
  316. SCM_VALIDATE_CHAR (SCM_ARGn, elt);
  317. j++;
  318. rest = SCM_CDR (rest);
  319. }
  320. rest = chrs;
  321. j = i;
  322. /* No need to scm_i_string_start_writing (), as the string isn't
  323. visible to any other thread. */
  324. while (j > 0 && scm_is_pair (rest))
  325. {
  326. SCM elt = SCM_CAR (rest);
  327. scm_i_string_set_x (result, j-1, SCM_CHAR (elt));
  328. rest = SCM_CDR (rest);
  329. j--;
  330. }
  331. }
  332. return result;
  333. }
  334. #undef FUNC_NAME
  335. SCM_SYMBOL (scm_sym_infix, "infix");
  336. SCM_SYMBOL (scm_sym_strict_infix, "strict-infix");
  337. SCM_SYMBOL (scm_sym_suffix, "suffix");
  338. SCM_SYMBOL (scm_sym_prefix, "prefix");
  339. SCM_DEFINE (scm_string_join, "string-join", 1, 2, 0,
  340. (SCM ls, SCM delimiter, SCM grammar),
  341. "Append the string in the string list @var{ls}, using the string\n"
  342. "@var{delimiter} as a delimiter between the elements of @var{ls}.\n"
  343. "@var{delimiter} defaults to @w{@samp{ }}, that is, strings in @var{ls}\n"
  344. "are appended with the space character in between them. @var{grammar} is\n"
  345. "a symbol which specifies how the delimiter is placed between the\n"
  346. "strings, and defaults to the symbol @code{infix}.\n"
  347. "\n"
  348. "@table @code\n"
  349. "@item infix\n"
  350. "Insert the separator between list elements. An empty string\n"
  351. "will produce an empty list.\n"
  352. "@item strict-infix\n"
  353. "Like @code{infix}, but will raise an error if given the empty\n"
  354. "list.\n"
  355. "@item suffix\n"
  356. "Insert the separator after every list element.\n"
  357. "@item prefix\n"
  358. "Insert the separator before each list element.\n"
  359. "@end table")
  360. #define FUNC_NAME s_scm_string_join
  361. {
  362. SCM append_list = SCM_EOL;
  363. long list_len = scm_ilength (ls);
  364. size_t delimiter_len = 0;
  365. /* Validate the string list. */
  366. if (list_len < 0)
  367. SCM_WRONG_TYPE_ARG (1, ls);
  368. /* Validate the delimiter and record its length. */
  369. if (SCM_UNBNDP (delimiter))
  370. {
  371. delimiter = scm_from_utf8_string (" ");
  372. delimiter_len = 1;
  373. }
  374. else
  375. {
  376. SCM_VALIDATE_STRING (2, delimiter);
  377. delimiter_len = scm_i_string_length (delimiter);
  378. }
  379. /* Validate the grammar symbol. */
  380. if (SCM_UNBNDP (grammar))
  381. grammar = scm_sym_infix;
  382. else if (!(scm_is_eq (grammar, scm_sym_infix)
  383. || scm_is_eq (grammar, scm_sym_strict_infix)
  384. || scm_is_eq (grammar, scm_sym_suffix)
  385. || scm_is_eq (grammar, scm_sym_prefix)))
  386. SCM_WRONG_TYPE_ARG (3, grammar);
  387. if (list_len == 0)
  388. {
  389. if (scm_is_eq (grammar, scm_sym_strict_infix))
  390. SCM_MISC_ERROR ("strict-infix grammar requires non-empty list",
  391. SCM_EOL);
  392. else
  393. /* Handle empty lists specially */
  394. append_list = SCM_EOL;
  395. }
  396. else if (delimiter_len == 0)
  397. /* Handle empty delimiters specially */
  398. append_list = ls;
  399. else
  400. {
  401. SCM *last_cdr_p = &append_list;
  402. #define ADD_TO_APPEND_LIST(x) \
  403. ((*last_cdr_p = scm_list_1 (x)), \
  404. (last_cdr_p = SCM_CDRLOC (*last_cdr_p)))
  405. /* Build a list of strings to pass to 'string-append'.
  406. Here we assume that 'ls' has at least one element. */
  407. /* If using the 'prefix' grammar, start with the delimiter. */
  408. if (scm_is_eq (grammar, scm_sym_prefix))
  409. ADD_TO_APPEND_LIST (delimiter);
  410. /* Handle the first element of 'ls' specially, so that in the loop
  411. that follows we can unconditionally insert the delimiter before
  412. every remaining element. */
  413. ADD_TO_APPEND_LIST (SCM_CAR (ls));
  414. ls = SCM_CDR (ls);
  415. /* Insert the delimiter before every remaining element. */
  416. while (scm_is_pair (ls))
  417. {
  418. ADD_TO_APPEND_LIST (delimiter);
  419. ADD_TO_APPEND_LIST (SCM_CAR (ls));
  420. ls = SCM_CDR (ls);
  421. }
  422. /* If using the 'suffix' grammar, add the delimiter to the end. */
  423. if (scm_is_eq (grammar, scm_sym_suffix))
  424. ADD_TO_APPEND_LIST (delimiter);
  425. #undef ADD_TO_APPEND_LIST
  426. }
  427. /* Construct the final result. */
  428. return scm_string_append (append_list);
  429. }
  430. #undef FUNC_NAME
  431. /* There are a number of functions to consider here for Scheme and C:
  432. string-copy STR [start [end]] ;; SRFI-13 variant of R5RS string-copy
  433. substring/copy STR start [end] ;; Guile variant of R5RS substring
  434. scm_string_copy (str) ;; Old function from Guile
  435. scm_substring_copy (str, [start, [end]])
  436. ;; C version of SRFI-13 string-copy
  437. ;; and C version of substring/copy
  438. The C function underlying string-copy is not exported to C
  439. programs. scm_substring_copy is defined in strings.c as the
  440. underlying function of substring/copy and allows an optional START
  441. argument.
  442. */
  443. SCM scm_srfi13_substring_copy (SCM str, SCM start, SCM end);
  444. SCM_DEFINE (scm_srfi13_substring_copy, "string-copy", 1, 2, 0,
  445. (SCM str, SCM start, SCM end),
  446. "Return a freshly allocated copy of the string @var{str}. If\n"
  447. "given, @var{start} and @var{end} delimit the portion of\n"
  448. "@var{str} which is copied.")
  449. #define FUNC_NAME s_scm_srfi13_substring_copy
  450. {
  451. size_t cstart, cend;
  452. MY_VALIDATE_SUBSTRING_SPEC (1, str,
  453. 2, start, cstart,
  454. 3, end, cend);
  455. return scm_i_substring_copy (str, cstart, cend);
  456. }
  457. #undef FUNC_NAME
  458. SCM
  459. scm_string_copy (SCM str)
  460. {
  461. if (!scm_is_string (str))
  462. scm_wrong_type_arg ("scm_string_copy", 0, str);
  463. return scm_i_substring (str, 0, scm_i_string_length (str));
  464. }
  465. SCM_DEFINE (scm_string_copy_x, "string-copy!", 3, 2, 0,
  466. (SCM target, SCM tstart, SCM s, SCM start, SCM end),
  467. "Copy the sequence of characters from index range [@var{start},\n"
  468. "@var{end}) in string @var{s} to string @var{target}, beginning\n"
  469. "at index @var{tstart}. The characters are copied left-to-right\n"
  470. "or right-to-left as needed -- the copy is guaranteed to work,\n"
  471. "even if @var{target} and @var{s} are the same string. It is an\n"
  472. "error if the copy operation runs off the end of the target\n"
  473. "string.")
  474. #define FUNC_NAME s_scm_string_copy_x
  475. {
  476. size_t cstart, cend, ctstart, dummy, len, i;
  477. SCM sdummy = SCM_UNDEFINED;
  478. MY_VALIDATE_SUBSTRING_SPEC (1, target,
  479. 2, tstart, ctstart,
  480. 2, sdummy, dummy);
  481. MY_VALIDATE_SUBSTRING_SPEC (3, s,
  482. 4, start, cstart,
  483. 5, end, cend);
  484. if (cstart < cend)
  485. {
  486. len = cend - cstart;
  487. SCM_ASSERT_RANGE (3, s, len <= scm_i_string_length (target) - ctstart);
  488. target = scm_i_string_start_writing (target);
  489. if (ctstart < cstart)
  490. {
  491. for (i = 0; i < len; i++)
  492. scm_i_string_set_x (target, ctstart + i,
  493. scm_i_string_ref (s, cstart + i));
  494. }
  495. else
  496. {
  497. for (i = len; i--;)
  498. scm_i_string_set_x (target, ctstart + i,
  499. scm_i_string_ref (s, cstart + i));
  500. }
  501. scm_i_string_stop_writing ();
  502. scm_remember_upto_here_1 (target);
  503. }
  504. return SCM_UNSPECIFIED;
  505. }
  506. #undef FUNC_NAME
  507. SCM_DEFINE (scm_substring_move_x, "substring-move!", 5, 0, 0,
  508. (SCM str1, SCM start1, SCM end1, SCM str2, SCM start2),
  509. "Copy the substring of @var{str1} bounded by @var{start1} and @var{end1}\n"
  510. "into @var{str2} beginning at position @var{start2}.\n"
  511. "@var{str1} and @var{str2} can be the same string.")
  512. #define FUNC_NAME s_scm_substring_move_x
  513. {
  514. return scm_string_copy_x (str2, start2, str1, start1, end1);
  515. }
  516. #undef FUNC_NAME
  517. SCM_DEFINE (scm_string_take, "string-take", 2, 0, 0,
  518. (SCM s, SCM n),
  519. "Return the @var{n} first characters of @var{s}.")
  520. #define FUNC_NAME s_scm_string_take
  521. {
  522. return scm_substring (s, SCM_INUM0, n);
  523. }
  524. #undef FUNC_NAME
  525. SCM_DEFINE (scm_string_drop, "string-drop", 2, 0, 0,
  526. (SCM s, SCM n),
  527. "Return all but the first @var{n} characters of @var{s}.")
  528. #define FUNC_NAME s_scm_string_drop
  529. {
  530. return scm_substring (s, n, SCM_UNDEFINED);
  531. }
  532. #undef FUNC_NAME
  533. SCM_DEFINE (scm_string_take_right, "string-take-right", 2, 0, 0,
  534. (SCM s, SCM n),
  535. "Return the @var{n} last characters of @var{s}.")
  536. #define FUNC_NAME s_scm_string_take_right
  537. {
  538. return scm_substring (s,
  539. scm_difference (scm_string_length (s), n),
  540. SCM_UNDEFINED);
  541. }
  542. #undef FUNC_NAME
  543. SCM_DEFINE (scm_string_drop_right, "string-drop-right", 2, 0, 0,
  544. (SCM s, SCM n),
  545. "Return all but the last @var{n} characters of @var{s}.")
  546. #define FUNC_NAME s_scm_string_drop_right
  547. {
  548. return scm_substring (s,
  549. SCM_INUM0,
  550. scm_difference (scm_string_length (s), n));
  551. }
  552. #undef FUNC_NAME
  553. SCM_DEFINE (scm_string_pad, "string-pad", 2, 3, 0,
  554. (SCM s, SCM len, SCM chr, SCM start, SCM end),
  555. "Take that characters from @var{start} to @var{end} from the\n"
  556. "string @var{s} and return a new string, right-padded by the\n"
  557. "character @var{chr} to length @var{len}. If the resulting\n"
  558. "string is longer than @var{len}, it is truncated on the right.")
  559. #define FUNC_NAME s_scm_string_pad
  560. {
  561. size_t cstart, cend, clen;
  562. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  563. 4, start, cstart,
  564. 5, end, cend);
  565. clen = scm_to_size_t (len);
  566. if (SCM_UNBNDP (chr))
  567. chr = SCM_MAKE_CHAR (' ');
  568. else
  569. {
  570. SCM_VALIDATE_CHAR (3, chr);
  571. }
  572. if (clen < (cend - cstart))
  573. return scm_i_substring (s, cend - clen, cend);
  574. else
  575. {
  576. SCM result;
  577. result = (scm_string_append
  578. (scm_list_2 (scm_c_make_string (clen - (cend - cstart), chr),
  579. scm_i_substring (s, cstart, cend))));
  580. return result;
  581. }
  582. }
  583. #undef FUNC_NAME
  584. SCM_DEFINE (scm_string_pad_right, "string-pad-right", 2, 3, 0,
  585. (SCM s, SCM len, SCM chr, SCM start, SCM end),
  586. "Take that characters from @var{start} to @var{end} from the\n"
  587. "string @var{s} and return a new string, left-padded by the\n"
  588. "character @var{chr} to length @var{len}. If the resulting\n"
  589. "string is longer than @var{len}, it is truncated on the left.")
  590. #define FUNC_NAME s_scm_string_pad_right
  591. {
  592. size_t cstart, cend, clen;
  593. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  594. 4, start, cstart,
  595. 5, end, cend);
  596. clen = scm_to_size_t (len);
  597. if (SCM_UNBNDP (chr))
  598. chr = SCM_MAKE_CHAR (' ');
  599. else
  600. {
  601. SCM_VALIDATE_CHAR (3, chr);
  602. }
  603. if (clen < (cend - cstart))
  604. return scm_i_substring (s, cstart, cstart + clen);
  605. else
  606. {
  607. SCM result;
  608. result = (scm_string_append
  609. (scm_list_2 (scm_i_substring (s, cstart, cend),
  610. scm_c_make_string (clen - (cend - cstart), chr))));
  611. return result;
  612. }
  613. }
  614. #undef FUNC_NAME
  615. SCM_DEFINE (scm_string_trim, "string-trim", 1, 3, 0,
  616. (SCM s, SCM char_pred, SCM start, SCM end),
  617. "Trim @var{s} by skipping over all characters on the left\n"
  618. "that satisfy the parameter @var{char_pred}:\n"
  619. "\n"
  620. "@itemize @bullet\n"
  621. "@item\n"
  622. "if it is the character @var{ch}, characters equal to\n"
  623. "@var{ch} are trimmed,\n"
  624. "\n"
  625. "@item\n"
  626. "if it is a procedure @var{pred} characters that\n"
  627. "satisfy @var{pred} are trimmed,\n"
  628. "\n"
  629. "@item\n"
  630. "if it is a character set, characters in that set are trimmed.\n"
  631. "@end itemize\n"
  632. "\n"
  633. "If called without a @var{char_pred} argument, all whitespace is\n"
  634. "trimmed.")
  635. #define FUNC_NAME s_scm_string_trim
  636. {
  637. size_t cstart, cend;
  638. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  639. 3, start, cstart,
  640. 4, end, cend);
  641. if (SCM_UNBNDP (char_pred)
  642. || scm_is_eq (char_pred, scm_char_set_whitespace))
  643. {
  644. while (cstart < cend)
  645. {
  646. if (!uc_is_c_whitespace (scm_i_string_ref (s, cstart)))
  647. break;
  648. cstart++;
  649. }
  650. }
  651. else if (SCM_CHARP (char_pred))
  652. {
  653. while (cstart < cend)
  654. {
  655. if (scm_i_string_ref (s, cstart) != SCM_CHAR (char_pred))
  656. break;
  657. cstart++;
  658. }
  659. }
  660. else if (SCM_CHARSETP (char_pred))
  661. {
  662. while (cstart < cend)
  663. {
  664. if (!REF_IN_CHARSET (s, cstart, char_pred))
  665. break;
  666. cstart++;
  667. }
  668. }
  669. else
  670. {
  671. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  672. char_pred, SCM_ARG2, FUNC_NAME);
  673. while (cstart < cend)
  674. {
  675. SCM res;
  676. res = scm_call_1 (char_pred, scm_c_make_char (scm_i_string_ref (s, cstart)));
  677. if (scm_is_false (res))
  678. break;
  679. cstart++;
  680. }
  681. }
  682. return scm_i_substring (s, cstart, cend);
  683. }
  684. #undef FUNC_NAME
  685. SCM_DEFINE (scm_string_trim_right, "string-trim-right", 1, 3, 0,
  686. (SCM s, SCM char_pred, SCM start, SCM end),
  687. "Trim @var{s} by skipping over all characters on the right\n"
  688. "that satisfy the parameter @var{char_pred}:\n"
  689. "\n"
  690. "@itemize @bullet\n"
  691. "@item\n"
  692. "if it is the character @var{ch}, characters equal to @var{ch}\n"
  693. "are trimmed,\n"
  694. "\n"
  695. "@item\n"
  696. "if it is a procedure @var{pred} characters that satisfy\n"
  697. "@var{pred} are trimmed,\n"
  698. "\n"
  699. "@item\n"
  700. "if it is a character sets, all characters in that set are\n"
  701. "trimmed.\n"
  702. "@end itemize\n"
  703. "\n"
  704. "If called without a @var{char_pred} argument, all whitespace is\n"
  705. "trimmed.")
  706. #define FUNC_NAME s_scm_string_trim_right
  707. {
  708. size_t cstart, cend;
  709. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  710. 3, start, cstart,
  711. 4, end, cend);
  712. if (SCM_UNBNDP (char_pred)
  713. || scm_is_eq (char_pred, scm_char_set_whitespace))
  714. {
  715. while (cstart < cend)
  716. {
  717. if (!uc_is_c_whitespace (scm_i_string_ref (s, cend - 1)))
  718. break;
  719. cend--;
  720. }
  721. }
  722. else if (SCM_CHARP (char_pred))
  723. {
  724. while (cstart < cend)
  725. {
  726. if (scm_i_string_ref (s, cend - 1) != SCM_CHAR (char_pred))
  727. break;
  728. cend--;
  729. }
  730. }
  731. else if (SCM_CHARSETP (char_pred))
  732. {
  733. while (cstart < cend)
  734. {
  735. if (!REF_IN_CHARSET (s, cend-1, char_pred))
  736. break;
  737. cend--;
  738. }
  739. }
  740. else
  741. {
  742. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  743. char_pred, SCM_ARG2, FUNC_NAME);
  744. while (cstart < cend)
  745. {
  746. SCM res;
  747. res = scm_call_1 (char_pred, scm_c_make_char (scm_i_string_ref (s, cend - 1)));
  748. if (scm_is_false (res))
  749. break;
  750. cend--;
  751. }
  752. }
  753. return scm_i_substring (s, cstart, cend);
  754. }
  755. #undef FUNC_NAME
  756. SCM_DEFINE (scm_string_trim_both, "string-trim-both", 1, 3, 0,
  757. (SCM s, SCM char_pred, SCM start, SCM end),
  758. "Trim @var{s} by skipping over all characters on both sides of\n"
  759. "the string that satisfy the parameter @var{char_pred}:\n"
  760. "\n"
  761. "@itemize @bullet\n"
  762. "@item\n"
  763. "if it is the character @var{ch}, characters equal to @var{ch}\n"
  764. "are trimmed,\n"
  765. "\n"
  766. "@item\n"
  767. "if it is a procedure @var{pred} characters that satisfy\n"
  768. "@var{pred} are trimmed,\n"
  769. "\n"
  770. "@item\n"
  771. "if it is a character set, the characters in the set are\n"
  772. "trimmed.\n"
  773. "@end itemize\n"
  774. "\n"
  775. "If called without a @var{char_pred} argument, all whitespace is\n"
  776. "trimmed.")
  777. #define FUNC_NAME s_scm_string_trim_both
  778. {
  779. size_t cstart, cend;
  780. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  781. 3, start, cstart,
  782. 4, end, cend);
  783. if (SCM_UNBNDP (char_pred)
  784. || scm_is_eq (char_pred, scm_char_set_whitespace))
  785. {
  786. while (cstart < cend)
  787. {
  788. if (!uc_is_c_whitespace (scm_i_string_ref (s, cstart)))
  789. break;
  790. cstart++;
  791. }
  792. while (cstart < cend)
  793. {
  794. if (!uc_is_c_whitespace (scm_i_string_ref (s, cend - 1)))
  795. break;
  796. cend--;
  797. }
  798. }
  799. else if (SCM_CHARP (char_pred))
  800. {
  801. while (cstart < cend)
  802. {
  803. if (scm_i_string_ref (s, cstart) != SCM_CHAR(char_pred))
  804. break;
  805. cstart++;
  806. }
  807. while (cstart < cend)
  808. {
  809. if (scm_i_string_ref (s, cend - 1) != SCM_CHAR (char_pred))
  810. break;
  811. cend--;
  812. }
  813. }
  814. else if (SCM_CHARSETP (char_pred))
  815. {
  816. while (cstart < cend)
  817. {
  818. if (!REF_IN_CHARSET (s, cstart, char_pred))
  819. break;
  820. cstart++;
  821. }
  822. while (cstart < cend)
  823. {
  824. if (!REF_IN_CHARSET (s, cend-1, char_pred))
  825. break;
  826. cend--;
  827. }
  828. }
  829. else
  830. {
  831. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  832. char_pred, SCM_ARG2, FUNC_NAME);
  833. while (cstart < cend)
  834. {
  835. SCM res;
  836. res = scm_call_1 (char_pred, scm_c_make_char (scm_i_string_ref (s, cstart)));
  837. if (scm_is_false (res))
  838. break;
  839. cstart++;
  840. }
  841. while (cstart < cend)
  842. {
  843. SCM res;
  844. res = scm_call_1 (char_pred, scm_c_make_char (scm_i_string_ref (s, cend - 1)));
  845. if (scm_is_false (res))
  846. break;
  847. cend--;
  848. }
  849. }
  850. return scm_i_substring (s, cstart, cend);
  851. }
  852. #undef FUNC_NAME
  853. SCM_DEFINE (scm_substring_fill_x, "string-fill!", 2, 2, 0,
  854. (SCM str, SCM chr, SCM start, SCM end),
  855. "Stores @var{chr} in every element of the given @var{str} and\n"
  856. "returns an unspecified value.")
  857. #define FUNC_NAME s_scm_substring_fill_x
  858. {
  859. size_t cstart, cend;
  860. size_t k;
  861. /* Older versions of Guile provided the function
  862. scm_substring_fill_x with the following order of arguments:
  863. str, start, end, chr
  864. We accomodate this here by detecting such a usage and reordering
  865. the arguments.
  866. */
  867. if (SCM_CHARP (end))
  868. {
  869. SCM tmp = end;
  870. end = start;
  871. start = chr;
  872. chr = tmp;
  873. }
  874. MY_VALIDATE_SUBSTRING_SPEC (1, str,
  875. 3, start, cstart,
  876. 4, end, cend);
  877. SCM_VALIDATE_CHAR (2, chr);
  878. if (cstart < cend)
  879. {
  880. str = scm_i_string_start_writing (str);
  881. for (k = cstart; k < cend; k++)
  882. scm_i_string_set_x (str, k, SCM_CHAR (chr));
  883. scm_i_string_stop_writing ();
  884. }
  885. return SCM_UNSPECIFIED;
  886. }
  887. #undef FUNC_NAME
  888. SCM
  889. scm_string_fill_x (SCM str, SCM chr)
  890. {
  891. return scm_substring_fill_x (str, chr, SCM_UNDEFINED, SCM_UNDEFINED);
  892. }
  893. SCM_DEFINE (scm_string_compare, "string-compare", 5, 4, 0,
  894. (SCM s1, SCM s2, SCM proc_lt, SCM proc_eq, SCM proc_gt, SCM start1, SCM end1, SCM start2, SCM end2),
  895. "Apply @var{proc_lt}, @var{proc_eq}, @var{proc_gt} to the\n"
  896. "mismatch index, depending upon whether @var{s1} is less than,\n"
  897. "equal to, or greater than @var{s2}. The mismatch index is the\n"
  898. "largest index @var{i} such that for every 0 <= @var{j} <\n"
  899. "@var{i}, @var{s1}[@var{j}] = @var{s2}[@var{j}] -- that is,\n"
  900. "@var{i} is the first position that does not match.")
  901. #define FUNC_NAME s_scm_string_compare
  902. {
  903. size_t cstart1, cend1, cstart2, cend2;
  904. SCM proc;
  905. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  906. 6, start1, cstart1,
  907. 7, end1, cend1);
  908. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  909. 8, start2, cstart2,
  910. 9, end2, cend2);
  911. SCM_VALIDATE_PROC (3, proc_lt);
  912. SCM_VALIDATE_PROC (4, proc_eq);
  913. SCM_VALIDATE_PROC (5, proc_gt);
  914. while (cstart1 < cend1 && cstart2 < cend2)
  915. {
  916. if (scm_i_string_ref (s1, cstart1)
  917. < scm_i_string_ref (s2, cstart2))
  918. {
  919. proc = proc_lt;
  920. goto ret;
  921. }
  922. else if (scm_i_string_ref (s1, cstart1)
  923. > scm_i_string_ref (s2, cstart2))
  924. {
  925. proc = proc_gt;
  926. goto ret;
  927. }
  928. cstart1++;
  929. cstart2++;
  930. }
  931. if (cstart1 < cend1)
  932. proc = proc_gt;
  933. else if (cstart2 < cend2)
  934. proc = proc_lt;
  935. else
  936. proc = proc_eq;
  937. ret:
  938. scm_remember_upto_here_2 (s1, s2);
  939. return scm_call_1 (proc, scm_from_size_t (cstart1));
  940. }
  941. #undef FUNC_NAME
  942. SCM_DEFINE (scm_string_compare_ci, "string-compare-ci", 5, 4, 0,
  943. (SCM s1, SCM s2, SCM proc_lt, SCM proc_eq, SCM proc_gt, SCM start1, SCM end1, SCM start2, SCM end2),
  944. "Apply @var{proc_lt}, @var{proc_eq}, @var{proc_gt} to the\n"
  945. "mismatch index, depending upon whether @var{s1} is less than,\n"
  946. "equal to, or greater than @var{s2}. The mismatch index is the\n"
  947. "largest index @var{i} such that for every 0 <= @var{j} <\n"
  948. "@var{i}, @var{s1}[@var{j}] = @var{s2}[@var{j}] -- that is,\n"
  949. "@var{i} is the first position where the lowercased letters \n"
  950. "do not match.\n")
  951. #define FUNC_NAME s_scm_string_compare_ci
  952. {
  953. size_t cstart1, cend1, cstart2, cend2;
  954. SCM proc;
  955. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  956. 6, start1, cstart1,
  957. 7, end1, cend1);
  958. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  959. 8, start2, cstart2,
  960. 9, end2, cend2);
  961. SCM_VALIDATE_PROC (3, proc_lt);
  962. SCM_VALIDATE_PROC (4, proc_eq);
  963. SCM_VALIDATE_PROC (5, proc_gt);
  964. while (cstart1 < cend1 && cstart2 < cend2)
  965. {
  966. if (uc_tolower (uc_toupper (scm_i_string_ref (s1, cstart1)))
  967. < uc_tolower (uc_toupper (scm_i_string_ref (s2, cstart2))))
  968. {
  969. proc = proc_lt;
  970. goto ret;
  971. }
  972. else if (uc_tolower (uc_toupper (scm_i_string_ref (s1, cstart1)))
  973. > uc_tolower (uc_toupper (scm_i_string_ref (s2, cstart2))))
  974. {
  975. proc = proc_gt;
  976. goto ret;
  977. }
  978. cstart1++;
  979. cstart2++;
  980. }
  981. if (cstart1 < cend1)
  982. proc = proc_gt;
  983. else if (cstart2 < cend2)
  984. proc = proc_lt;
  985. else
  986. proc = proc_eq;
  987. ret:
  988. scm_remember_upto_here (s1, s2);
  989. return scm_call_1 (proc, scm_from_size_t (cstart1));
  990. }
  991. #undef FUNC_NAME
  992. /* This function compares two substrings, S1 from START1 to END1 and
  993. S2 from START2 to END2, possibly case insensitively, and returns
  994. one of the parameters LESSTHAN, GREATERTHAN, SHORTER, LONGER, or
  995. EQUAL depending if S1 is less than S2, greater than S2, shorter,
  996. longer, or equal. */
  997. static SCM
  998. compare_strings (const char *fname, int case_insensitive,
  999. SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2,
  1000. SCM lessthan, SCM greaterthan, SCM shorter, SCM longer, SCM equal)
  1001. {
  1002. size_t cstart1, cend1, cstart2, cend2;
  1003. SCM ret;
  1004. scm_t_wchar a, b;
  1005. MY_SUBF_VALIDATE_SUBSTRING_SPEC (fname, 1, s1,
  1006. 3, start1, cstart1,
  1007. 4, end1, cend1);
  1008. MY_SUBF_VALIDATE_SUBSTRING_SPEC (fname, 2, s2,
  1009. 5, start2, cstart2,
  1010. 6, end2, cend2);
  1011. while (cstart1 < cend1 && cstart2 < cend2)
  1012. {
  1013. if (case_insensitive)
  1014. {
  1015. a = uc_tolower (uc_toupper (scm_i_string_ref (s1, cstart1)));
  1016. b = uc_tolower (uc_toupper (scm_i_string_ref (s2, cstart2)));
  1017. }
  1018. else
  1019. {
  1020. a = scm_i_string_ref (s1, cstart1);
  1021. b = scm_i_string_ref (s2, cstart2);
  1022. }
  1023. if (a < b)
  1024. {
  1025. ret = lessthan;
  1026. goto done;
  1027. }
  1028. else if (a > b)
  1029. {
  1030. ret = greaterthan;
  1031. goto done;
  1032. }
  1033. cstart1++;
  1034. cstart2++;
  1035. }
  1036. if (cstart1 < cend1)
  1037. {
  1038. ret = longer;
  1039. goto done;
  1040. }
  1041. else if (cstart2 < cend2)
  1042. {
  1043. ret = shorter;
  1044. goto done;
  1045. }
  1046. else
  1047. {
  1048. ret = equal;
  1049. goto done;
  1050. }
  1051. done:
  1052. scm_remember_upto_here_2 (s1, s2);
  1053. return ret;
  1054. }
  1055. SCM_DEFINE (scm_string_eq, "string=", 2, 4, 0,
  1056. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1057. "Return @code{#f} if @var{s1} and @var{s2} are not equal, a true\n"
  1058. "value otherwise.")
  1059. #define FUNC_NAME s_scm_string_eq
  1060. {
  1061. if (SCM_LIKELY (scm_is_string (s1) && scm_is_string (s2) &&
  1062. scm_i_is_narrow_string (s1) == scm_i_is_narrow_string (s2)
  1063. && SCM_UNBNDP (start1) && SCM_UNBNDP (end1)
  1064. && SCM_UNBNDP (start2) && SCM_UNBNDP (end2)))
  1065. {
  1066. /* Fast path for this common case, which avoids the repeated calls to
  1067. `scm_i_string_ref'. */
  1068. size_t len1, len2;
  1069. len1 = scm_i_string_length (s1);
  1070. len2 = scm_i_string_length (s2);
  1071. if (len1 != len2)
  1072. return SCM_BOOL_F;
  1073. else
  1074. {
  1075. if (!scm_i_is_narrow_string (s1))
  1076. len1 *= 4;
  1077. return scm_from_bool (memcmp (scm_i_string_data (s1),
  1078. scm_i_string_data (s2),
  1079. len1) == 0);
  1080. }
  1081. }
  1082. return compare_strings (FUNC_NAME, 0,
  1083. s1, s2, start1, end1, start2, end2,
  1084. SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_T);
  1085. }
  1086. #undef FUNC_NAME
  1087. SCM_DEFINE (scm_string_neq, "string<>", 2, 4, 0,
  1088. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1089. "Return @code{#f} if @var{s1} and @var{s2} are equal, a true\n"
  1090. "value otherwise.")
  1091. #define FUNC_NAME s_scm_string_neq
  1092. {
  1093. return compare_strings (FUNC_NAME, 0,
  1094. s1, s2, start1, end1, start2, end2,
  1095. SCM_BOOL_T, SCM_BOOL_T, SCM_BOOL_T, SCM_BOOL_T, SCM_BOOL_F);
  1096. }
  1097. #undef FUNC_NAME
  1098. SCM_DEFINE (scm_string_lt, "string<", 2, 4, 0,
  1099. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1100. "Return @code{#f} if @var{s1} is greater or equal to @var{s2}, a\n"
  1101. "true value otherwise.")
  1102. #define FUNC_NAME s_scm_string_lt
  1103. {
  1104. return compare_strings (FUNC_NAME, 0,
  1105. s1, s2, start1, end1, start2, end2,
  1106. SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_F);
  1107. }
  1108. #undef FUNC_NAME
  1109. SCM_DEFINE (scm_string_gt, "string>", 2, 4, 0,
  1110. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1111. "Return @code{#f} if @var{s1} is less or equal to @var{s2}, a\n"
  1112. "true value otherwise.")
  1113. #define FUNC_NAME s_scm_string_gt
  1114. {
  1115. return compare_strings (FUNC_NAME, 0,
  1116. s1, s2, start1, end1, start2, end2,
  1117. SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_F);
  1118. }
  1119. #undef FUNC_NAME
  1120. SCM_DEFINE (scm_string_le, "string<=", 2, 4, 0,
  1121. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1122. "Return @code{#f} if @var{s1} is greater to @var{s2}, a true\n"
  1123. "value otherwise.")
  1124. #define FUNC_NAME s_scm_string_le
  1125. {
  1126. return compare_strings (FUNC_NAME, 0,
  1127. s1, s2, start1, end1, start2, end2,
  1128. SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_T);
  1129. }
  1130. #undef FUNC_NAME
  1131. SCM_DEFINE (scm_string_ge, "string>=", 2, 4, 0,
  1132. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1133. "Return @code{#f} if @var{s1} is less to @var{s2}, a true value\n"
  1134. "otherwise.")
  1135. #define FUNC_NAME s_scm_string_ge
  1136. {
  1137. return compare_strings (FUNC_NAME, 0,
  1138. s1, s2, start1, end1, start2, end2,
  1139. SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_T);
  1140. }
  1141. #undef FUNC_NAME
  1142. SCM_DEFINE (scm_string_ci_eq, "string-ci=", 2, 4, 0,
  1143. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1144. "Return @code{#f} if @var{s1} and @var{s2} are not equal, a true\n"
  1145. "value otherwise. The character comparison is done\n"
  1146. "case-insensitively.")
  1147. #define FUNC_NAME s_scm_string_ci_eq
  1148. {
  1149. return compare_strings (FUNC_NAME, 1,
  1150. s1, s2, start1, end1, start2, end2,
  1151. SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_T);
  1152. }
  1153. #undef FUNC_NAME
  1154. SCM_DEFINE (scm_string_ci_neq, "string-ci<>", 2, 4, 0,
  1155. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1156. "Return @code{#f} if @var{s1} and @var{s2} are equal, a true\n"
  1157. "value otherwise. The character comparison is done\n"
  1158. "case-insensitively.")
  1159. #define FUNC_NAME s_scm_string_ci_neq
  1160. {
  1161. return compare_strings (FUNC_NAME, 1,
  1162. s1, s2, start1, end1, start2, end2,
  1163. SCM_BOOL_T, SCM_BOOL_T, SCM_BOOL_T, SCM_BOOL_T, SCM_BOOL_F);
  1164. }
  1165. #undef FUNC_NAME
  1166. SCM_DEFINE (scm_string_ci_lt, "string-ci<", 2, 4, 0,
  1167. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1168. "Return @code{#f} if @var{s1} is greater or equal to @var{s2}, a\n"
  1169. "true value otherwise. The character comparison is done\n"
  1170. "case-insensitively.")
  1171. #define FUNC_NAME s_scm_string_ci_lt
  1172. {
  1173. return compare_strings (FUNC_NAME, 1,
  1174. s1, s2, start1, end1, start2, end2,
  1175. SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_F);
  1176. }
  1177. #undef FUNC_NAME
  1178. SCM_DEFINE (scm_string_ci_gt, "string-ci>", 2, 4, 0,
  1179. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1180. "Return @code{#f} if @var{s1} is less or equal to @var{s2}, a\n"
  1181. "true value otherwise. The character comparison is done\n"
  1182. "case-insensitively.")
  1183. #define FUNC_NAME s_scm_string_ci_gt
  1184. {
  1185. return compare_strings (FUNC_NAME, 1,
  1186. s1, s2, start1, end1, start2, end2,
  1187. SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_F);
  1188. }
  1189. #undef FUNC_NAME
  1190. SCM_DEFINE (scm_string_ci_le, "string-ci<=", 2, 4, 0,
  1191. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1192. "Return @code{#f} if @var{s1} is greater to @var{s2}, a true\n"
  1193. "value otherwise. The character comparison is done\n"
  1194. "case-insensitively.")
  1195. #define FUNC_NAME s_scm_string_ci_le
  1196. {
  1197. return compare_strings (FUNC_NAME, 1,
  1198. s1, s2, start1, end1, start2, end2,
  1199. SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_T);
  1200. }
  1201. #undef FUNC_NAME
  1202. SCM_DEFINE (scm_string_ci_ge, "string-ci>=", 2, 4, 0,
  1203. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1204. "Return @code{#f} if @var{s1} is less to @var{s2}, a true value\n"
  1205. "otherwise. The character comparison is done\n"
  1206. "case-insensitively.")
  1207. #define FUNC_NAME s_scm_string_ci_ge
  1208. {
  1209. return compare_strings (FUNC_NAME, 1,
  1210. s1, s2, start1, end1, start2, end2,
  1211. SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_F, SCM_BOOL_T, SCM_BOOL_T);
  1212. }
  1213. #undef FUNC_NAME
  1214. SCM_DEFINE (scm_substring_hash, "string-hash", 1, 3, 0,
  1215. (SCM s, SCM bound, SCM start, SCM end),
  1216. "Compute a hash value for @var{s}. the optional argument "
  1217. "@var{bound} is a non-negative exact "
  1218. "integer specifying the range of the hash function. "
  1219. "A positive value restricts the return value to the "
  1220. "range [0,bound).")
  1221. #define FUNC_NAME s_scm_substring_hash
  1222. {
  1223. if (SCM_UNBNDP (bound))
  1224. bound = scm_from_intmax (SCM_MOST_POSITIVE_FIXNUM);
  1225. if (SCM_UNBNDP (start))
  1226. start = SCM_INUM0;
  1227. return scm_hash (scm_substring_shared (s, start, end), bound);
  1228. }
  1229. #undef FUNC_NAME
  1230. SCM_DEFINE (scm_substring_hash_ci, "string-hash-ci", 1, 3, 0,
  1231. (SCM s, SCM bound, SCM start, SCM end),
  1232. "Compute a hash value for @var{s}. the optional argument "
  1233. "@var{bound} is a non-negative exact "
  1234. "integer specifying the range of the hash function. "
  1235. "A positive value restricts the return value to the "
  1236. "range [0,bound).")
  1237. #define FUNC_NAME s_scm_substring_hash_ci
  1238. {
  1239. return scm_substring_hash (scm_substring_downcase (s, start, end),
  1240. bound,
  1241. SCM_UNDEFINED, SCM_UNDEFINED);
  1242. }
  1243. #undef FUNC_NAME
  1244. SCM_DEFINE (scm_string_prefix_length, "string-prefix-length", 2, 4, 0,
  1245. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1246. "Return the length of the longest common prefix of the two\n"
  1247. "strings.")
  1248. #define FUNC_NAME s_scm_string_prefix_length
  1249. {
  1250. size_t cstart1, cend1, cstart2, cend2;
  1251. size_t len = 0;
  1252. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  1253. 3, start1, cstart1,
  1254. 4, end1, cend1);
  1255. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  1256. 5, start2, cstart2,
  1257. 6, end2, cend2);
  1258. while (cstart1 < cend1 && cstart2 < cend2)
  1259. {
  1260. if (scm_i_string_ref (s1, cstart1)
  1261. != scm_i_string_ref (s2, cstart2))
  1262. goto ret;
  1263. len++;
  1264. cstart1++;
  1265. cstart2++;
  1266. }
  1267. ret:
  1268. scm_remember_upto_here_2 (s1, s2);
  1269. return scm_from_size_t (len);
  1270. }
  1271. #undef FUNC_NAME
  1272. SCM_DEFINE (scm_string_prefix_length_ci, "string-prefix-length-ci", 2, 4, 0,
  1273. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1274. "Return the length of the longest common prefix of the two\n"
  1275. "strings, ignoring character case.")
  1276. #define FUNC_NAME s_scm_string_prefix_length_ci
  1277. {
  1278. size_t cstart1, cend1, cstart2, cend2;
  1279. size_t len = 0;
  1280. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  1281. 3, start1, cstart1,
  1282. 4, end1, cend1);
  1283. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  1284. 5, start2, cstart2,
  1285. 6, end2, cend2);
  1286. while (cstart1 < cend1 && cstart2 < cend2)
  1287. {
  1288. if (uc_tolower (uc_toupper (scm_i_string_ref (s1, cstart1)))
  1289. != uc_tolower (uc_toupper (scm_i_string_ref (s2, cstart2))))
  1290. goto ret;
  1291. len++;
  1292. cstart1++;
  1293. cstart2++;
  1294. }
  1295. ret:
  1296. scm_remember_upto_here_2 (s1, s2);
  1297. return scm_from_size_t (len);
  1298. }
  1299. #undef FUNC_NAME
  1300. SCM_DEFINE (scm_string_suffix_length, "string-suffix-length", 2, 4, 0,
  1301. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1302. "Return the length of the longest common suffix of the two\n"
  1303. "strings.")
  1304. #define FUNC_NAME s_scm_string_suffix_length
  1305. {
  1306. size_t cstart1, cend1, cstart2, cend2;
  1307. size_t len = 0;
  1308. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  1309. 3, start1, cstart1,
  1310. 4, end1, cend1);
  1311. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  1312. 5, start2, cstart2,
  1313. 6, end2, cend2);
  1314. while (cstart1 < cend1 && cstart2 < cend2)
  1315. {
  1316. cend1--;
  1317. cend2--;
  1318. if (scm_i_string_ref (s1, cend1)
  1319. != scm_i_string_ref (s2, cend2))
  1320. goto ret;
  1321. len++;
  1322. }
  1323. ret:
  1324. scm_remember_upto_here_2 (s1, s2);
  1325. return scm_from_size_t (len);
  1326. }
  1327. #undef FUNC_NAME
  1328. SCM_DEFINE (scm_string_suffix_length_ci, "string-suffix-length-ci", 2, 4, 0,
  1329. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1330. "Return the length of the longest common suffix of the two\n"
  1331. "strings, ignoring character case.")
  1332. #define FUNC_NAME s_scm_string_suffix_length_ci
  1333. {
  1334. size_t cstart1, cend1, cstart2, cend2;
  1335. size_t len = 0;
  1336. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  1337. 3, start1, cstart1,
  1338. 4, end1, cend1);
  1339. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  1340. 5, start2, cstart2,
  1341. 6, end2, cend2);
  1342. while (cstart1 < cend1 && cstart2 < cend2)
  1343. {
  1344. cend1--;
  1345. cend2--;
  1346. if (uc_tolower (uc_toupper (scm_i_string_ref (s1, cend1)))
  1347. != uc_tolower (uc_toupper (scm_i_string_ref (s2, cend2))))
  1348. goto ret;
  1349. len++;
  1350. }
  1351. ret:
  1352. scm_remember_upto_here_2 (s1, s2);
  1353. return scm_from_size_t (len);
  1354. }
  1355. #undef FUNC_NAME
  1356. SCM_DEFINE (scm_string_prefix_p, "string-prefix?", 2, 4, 0,
  1357. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1358. "Is @var{s1} a prefix of @var{s2}?")
  1359. #define FUNC_NAME s_scm_string_prefix_p
  1360. {
  1361. size_t cstart1, cend1, cstart2, cend2;
  1362. size_t len = 0, len1;
  1363. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  1364. 3, start1, cstart1,
  1365. 4, end1, cend1);
  1366. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  1367. 5, start2, cstart2,
  1368. 6, end2, cend2);
  1369. len1 = cend1 - cstart1;
  1370. while (cstart1 < cend1 && cstart2 < cend2)
  1371. {
  1372. if (scm_i_string_ref (s1, cstart1)
  1373. != scm_i_string_ref (s2, cstart2))
  1374. goto ret;
  1375. len++;
  1376. cstart1++;
  1377. cstart2++;
  1378. }
  1379. ret:
  1380. scm_remember_upto_here_2 (s1, s2);
  1381. return scm_from_bool (len == len1);
  1382. }
  1383. #undef FUNC_NAME
  1384. SCM_DEFINE (scm_string_prefix_ci_p, "string-prefix-ci?", 2, 4, 0,
  1385. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1386. "Is @var{s1} a prefix of @var{s2}, ignoring character case?")
  1387. #define FUNC_NAME s_scm_string_prefix_ci_p
  1388. {
  1389. size_t cstart1, cend1, cstart2, cend2;
  1390. size_t len = 0, len1;
  1391. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  1392. 3, start1, cstart1,
  1393. 4, end1, cend1);
  1394. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  1395. 5, start2, cstart2,
  1396. 6, end2, cend2);
  1397. len1 = cend1 - cstart1;
  1398. while (cstart1 < cend1 && cstart2 < cend2)
  1399. {
  1400. scm_t_wchar a = uc_tolower (uc_toupper (scm_i_string_ref (s1, cstart1)));
  1401. scm_t_wchar b = uc_tolower (uc_toupper (scm_i_string_ref (s2, cstart2)));
  1402. if (a != b)
  1403. goto ret;
  1404. len++;
  1405. cstart1++;
  1406. cstart2++;
  1407. }
  1408. ret:
  1409. scm_remember_upto_here_2 (s1, s2);
  1410. return scm_from_bool (len == len1);
  1411. }
  1412. #undef FUNC_NAME
  1413. SCM_DEFINE (scm_string_suffix_p, "string-suffix?", 2, 4, 0,
  1414. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1415. "Is @var{s1} a suffix of @var{s2}?")
  1416. #define FUNC_NAME s_scm_string_suffix_p
  1417. {
  1418. size_t cstart1, cend1, cstart2, cend2;
  1419. size_t len = 0, len1;
  1420. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  1421. 3, start1, cstart1,
  1422. 4, end1, cend1);
  1423. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  1424. 5, start2, cstart2,
  1425. 6, end2, cend2);
  1426. len1 = cend1 - cstart1;
  1427. while (cstart1 < cend1 && cstart2 < cend2)
  1428. {
  1429. cend1--;
  1430. cend2--;
  1431. if (scm_i_string_ref (s1, cend1)
  1432. != scm_i_string_ref (s2, cend2))
  1433. goto ret;
  1434. len++;
  1435. }
  1436. ret:
  1437. scm_remember_upto_here_2 (s1, s2);
  1438. return scm_from_bool (len == len1);
  1439. }
  1440. #undef FUNC_NAME
  1441. SCM_DEFINE (scm_string_suffix_ci_p, "string-suffix-ci?", 2, 4, 0,
  1442. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1443. "Is @var{s1} a suffix of @var{s2}, ignoring character case?")
  1444. #define FUNC_NAME s_scm_string_suffix_ci_p
  1445. {
  1446. size_t cstart1, cend1, cstart2, cend2;
  1447. size_t len = 0, len1;
  1448. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  1449. 3, start1, cstart1,
  1450. 4, end1, cend1);
  1451. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  1452. 5, start2, cstart2,
  1453. 6, end2, cend2);
  1454. len1 = cend1 - cstart1;
  1455. while (cstart1 < cend1 && cstart2 < cend2)
  1456. {
  1457. cend1--;
  1458. cend2--;
  1459. if (uc_tolower (uc_toupper (scm_i_string_ref (s1, cend1)))
  1460. != uc_tolower (uc_toupper (scm_i_string_ref (s2, cend2))))
  1461. goto ret;
  1462. len++;
  1463. }
  1464. ret:
  1465. scm_remember_upto_here_2 (s1, s2);
  1466. return scm_from_bool (len == len1);
  1467. }
  1468. #undef FUNC_NAME
  1469. SCM_DEFINE (scm_string_index, "string-index", 2, 2, 0,
  1470. (SCM s, SCM char_pred, SCM start, SCM end),
  1471. "Search through the string @var{s} from left to right, returning\n"
  1472. "the index of the first occurrence of a character which\n"
  1473. "\n"
  1474. "@itemize @bullet\n"
  1475. "@item\n"
  1476. "equals @var{char_pred}, if it is character,\n"
  1477. "\n"
  1478. "@item\n"
  1479. "satisfies the predicate @var{char_pred}, if it is a procedure,\n"
  1480. "\n"
  1481. "@item\n"
  1482. "is in the set @var{char_pred}, if it is a character set.\n"
  1483. "@end itemize\n\n"
  1484. "Return @code{#f} if no match is found.")
  1485. #define FUNC_NAME s_scm_string_index
  1486. {
  1487. size_t cstart, cend;
  1488. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  1489. 3, start, cstart,
  1490. 4, end, cend);
  1491. if (SCM_CHARP (char_pred))
  1492. {
  1493. while (cstart < cend)
  1494. {
  1495. if (scm_i_string_ref (s, cstart) == SCM_CHAR (char_pred))
  1496. goto found;
  1497. cstart++;
  1498. }
  1499. }
  1500. else if (SCM_CHARSETP (char_pred))
  1501. {
  1502. while (cstart < cend)
  1503. {
  1504. if (REF_IN_CHARSET (s, cstart, char_pred))
  1505. goto found;
  1506. cstart++;
  1507. }
  1508. }
  1509. else
  1510. {
  1511. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  1512. char_pred, SCM_ARG2, FUNC_NAME);
  1513. while (cstart < cend)
  1514. {
  1515. SCM res;
  1516. res = scm_call_1 (char_pred, scm_c_make_char (scm_i_string_ref (s, cstart)));
  1517. if (scm_is_true (res))
  1518. goto found;
  1519. cstart++;
  1520. }
  1521. }
  1522. scm_remember_upto_here_1 (s);
  1523. return SCM_BOOL_F;
  1524. found:
  1525. scm_remember_upto_here_1 (s);
  1526. return scm_from_size_t (cstart);
  1527. }
  1528. #undef FUNC_NAME
  1529. SCM_DEFINE (scm_string_index_right, "string-index-right", 2, 2, 0,
  1530. (SCM s, SCM char_pred, SCM start, SCM end),
  1531. "Search through the string @var{s} from right to left, returning\n"
  1532. "the index of the last occurrence of a character which\n"
  1533. "\n"
  1534. "@itemize @bullet\n"
  1535. "@item\n"
  1536. "equals @var{char_pred}, if it is character,\n"
  1537. "\n"
  1538. "@item\n"
  1539. "satisfies the predicate @var{char_pred}, if it is a procedure,\n"
  1540. "\n"
  1541. "@item\n"
  1542. "is in the set if @var{char_pred} is a character set.\n"
  1543. "@end itemize\n\n"
  1544. "Return @code{#f} if no match is found.")
  1545. #define FUNC_NAME s_scm_string_index_right
  1546. {
  1547. size_t cstart, cend;
  1548. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  1549. 3, start, cstart,
  1550. 4, end, cend);
  1551. if (SCM_CHARP (char_pred))
  1552. {
  1553. while (cstart < cend)
  1554. {
  1555. cend--;
  1556. if (scm_i_string_ref (s, cend) == SCM_CHAR (char_pred))
  1557. goto found;
  1558. }
  1559. }
  1560. else if (SCM_CHARSETP (char_pred))
  1561. {
  1562. while (cstart < cend)
  1563. {
  1564. cend--;
  1565. if (REF_IN_CHARSET (s, cend, char_pred))
  1566. goto found;
  1567. }
  1568. }
  1569. else
  1570. {
  1571. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  1572. char_pred, SCM_ARG2, FUNC_NAME);
  1573. while (cstart < cend)
  1574. {
  1575. SCM res;
  1576. cend--;
  1577. res = scm_call_1 (char_pred, scm_c_make_char (scm_i_string_ref (s, cend)));
  1578. if (scm_is_true (res))
  1579. goto found;
  1580. }
  1581. }
  1582. scm_remember_upto_here_1 (s);
  1583. return SCM_BOOL_F;
  1584. found:
  1585. scm_remember_upto_here_1 (s);
  1586. return scm_from_size_t (cend);
  1587. }
  1588. #undef FUNC_NAME
  1589. SCM_DEFINE (scm_string_rindex, "string-rindex", 2, 2, 0,
  1590. (SCM s, SCM char_pred, SCM start, SCM end),
  1591. "Search through the string @var{s} from right to left, returning\n"
  1592. "the index of the last occurrence of a character which\n"
  1593. "\n"
  1594. "@itemize @bullet\n"
  1595. "@item\n"
  1596. "equals @var{char_pred}, if it is character,\n"
  1597. "\n"
  1598. "@item\n"
  1599. "satisfies the predicate @var{char_pred}, if it is a procedure,\n"
  1600. "\n"
  1601. "@item\n"
  1602. "is in the set if @var{char_pred} is a character set.\n"
  1603. "@end itemize\n\n"
  1604. "Return @code{#f} if no match is found.")
  1605. #define FUNC_NAME s_scm_string_rindex
  1606. {
  1607. return scm_string_index_right (s, char_pred, start, end);
  1608. }
  1609. #undef FUNC_NAME
  1610. SCM_DEFINE (scm_string_skip, "string-skip", 2, 2, 0,
  1611. (SCM s, SCM char_pred, SCM start, SCM end),
  1612. "Search through the string @var{s} from left to right, returning\n"
  1613. "the index of the first occurrence of a character which\n"
  1614. "\n"
  1615. "@itemize @bullet\n"
  1616. "@item\n"
  1617. "does not equal @var{char_pred}, if it is character,\n"
  1618. "\n"
  1619. "@item\n"
  1620. "does not satisfy the predicate @var{char_pred}, if it is a\n"
  1621. "procedure,\n"
  1622. "\n"
  1623. "@item\n"
  1624. "is not in the set if @var{char_pred} is a character set.\n"
  1625. "@end itemize")
  1626. #define FUNC_NAME s_scm_string_skip
  1627. {
  1628. size_t cstart, cend;
  1629. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  1630. 3, start, cstart,
  1631. 4, end, cend);
  1632. if (SCM_CHARP (char_pred))
  1633. {
  1634. while (cstart < cend)
  1635. {
  1636. if (scm_i_string_ref (s, cstart) != SCM_CHAR (char_pred))
  1637. goto found;
  1638. cstart++;
  1639. }
  1640. }
  1641. else if (SCM_CHARSETP (char_pred))
  1642. {
  1643. while (cstart < cend)
  1644. {
  1645. if (!REF_IN_CHARSET (s, cstart, char_pred))
  1646. goto found;
  1647. cstart++;
  1648. }
  1649. }
  1650. else
  1651. {
  1652. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  1653. char_pred, SCM_ARG2, FUNC_NAME);
  1654. while (cstart < cend)
  1655. {
  1656. SCM res;
  1657. res = scm_call_1 (char_pred, scm_c_make_char (scm_i_string_ref (s, cstart)));
  1658. if (scm_is_false (res))
  1659. goto found;
  1660. cstart++;
  1661. }
  1662. }
  1663. scm_remember_upto_here_1 (s);
  1664. return SCM_BOOL_F;
  1665. found:
  1666. scm_remember_upto_here_1 (s);
  1667. return scm_from_size_t (cstart);
  1668. }
  1669. #undef FUNC_NAME
  1670. SCM_DEFINE (scm_string_skip_right, "string-skip-right", 2, 2, 0,
  1671. (SCM s, SCM char_pred, SCM start, SCM end),
  1672. "Search through the string @var{s} from right to left, returning\n"
  1673. "the index of the last occurrence of a character which\n"
  1674. "\n"
  1675. "@itemize @bullet\n"
  1676. "@item\n"
  1677. "does not equal @var{char_pred}, if it is character,\n"
  1678. "\n"
  1679. "@item\n"
  1680. "does not satisfy the predicate @var{char_pred}, if it is a\n"
  1681. "procedure,\n"
  1682. "\n"
  1683. "@item\n"
  1684. "is not in the set if @var{char_pred} is a character set.\n"
  1685. "@end itemize")
  1686. #define FUNC_NAME s_scm_string_skip_right
  1687. {
  1688. size_t cstart, cend;
  1689. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  1690. 3, start, cstart,
  1691. 4, end, cend);
  1692. if (SCM_CHARP (char_pred))
  1693. {
  1694. while (cstart < cend)
  1695. {
  1696. cend--;
  1697. if (scm_i_string_ref (s, cend) != SCM_CHAR (char_pred))
  1698. goto found;
  1699. }
  1700. }
  1701. else if (SCM_CHARSETP (char_pred))
  1702. {
  1703. while (cstart < cend)
  1704. {
  1705. cend--;
  1706. if (!REF_IN_CHARSET (s, cend, char_pred))
  1707. goto found;
  1708. }
  1709. }
  1710. else
  1711. {
  1712. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  1713. char_pred, SCM_ARG2, FUNC_NAME);
  1714. while (cstart < cend)
  1715. {
  1716. SCM res;
  1717. cend--;
  1718. res = scm_call_1 (char_pred, scm_c_make_char (scm_i_string_ref (s, cend)));
  1719. if (scm_is_false (res))
  1720. goto found;
  1721. }
  1722. }
  1723. scm_remember_upto_here_1 (s);
  1724. return SCM_BOOL_F;
  1725. found:
  1726. scm_remember_upto_here_1 (s);
  1727. return scm_from_size_t (cend);
  1728. }
  1729. #undef FUNC_NAME
  1730. SCM_DEFINE (scm_string_count, "string-count", 2, 2, 0,
  1731. (SCM s, SCM char_pred, SCM start, SCM end),
  1732. "Return the count of the number of characters in the string\n"
  1733. "@var{s} which\n"
  1734. "\n"
  1735. "@itemize @bullet\n"
  1736. "@item\n"
  1737. "equals @var{char_pred}, if it is character,\n"
  1738. "\n"
  1739. "@item\n"
  1740. "satisfies the predicate @var{char_pred}, if it is a procedure.\n"
  1741. "\n"
  1742. "@item\n"
  1743. "is in the set @var{char_pred}, if it is a character set.\n"
  1744. "@end itemize")
  1745. #define FUNC_NAME s_scm_string_count
  1746. {
  1747. size_t cstart, cend;
  1748. size_t count = 0;
  1749. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  1750. 3, start, cstart,
  1751. 4, end, cend);
  1752. if (SCM_CHARP (char_pred))
  1753. {
  1754. while (cstart < cend)
  1755. {
  1756. if (scm_i_string_ref (s, cstart) == SCM_CHAR(char_pred))
  1757. count++;
  1758. cstart++;
  1759. }
  1760. }
  1761. else if (SCM_CHARSETP (char_pred))
  1762. {
  1763. while (cstart < cend)
  1764. {
  1765. if (REF_IN_CHARSET (s, cstart, char_pred))
  1766. count++;
  1767. cstart++;
  1768. }
  1769. }
  1770. else
  1771. {
  1772. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  1773. char_pred, SCM_ARG2, FUNC_NAME);
  1774. while (cstart < cend)
  1775. {
  1776. SCM res;
  1777. res = scm_call_1 (char_pred, scm_c_make_char (scm_i_string_ref (s, cstart)));
  1778. if (scm_is_true (res))
  1779. count++;
  1780. cstart++;
  1781. }
  1782. }
  1783. scm_remember_upto_here_1 (s);
  1784. return scm_from_size_t (count);
  1785. }
  1786. #undef FUNC_NAME
  1787. /* FIXME::martin: This should definitely get implemented more
  1788. efficiently -- maybe with Knuth-Morris-Pratt, like in the reference
  1789. implementation. */
  1790. SCM_DEFINE (scm_string_contains, "string-contains", 2, 4, 0,
  1791. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1792. "Does string @var{s1} contain string @var{s2}? Return the index\n"
  1793. "in @var{s1} where @var{s2} occurs as a substring, or false.\n"
  1794. "The optional start/end indices restrict the operation to the\n"
  1795. "indicated substrings.")
  1796. #define FUNC_NAME s_scm_string_contains
  1797. {
  1798. size_t cstart1, cend1, cstart2, cend2;
  1799. size_t len2, i, j;
  1800. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  1801. 3, start1, cstart1,
  1802. 4, end1, cend1);
  1803. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  1804. 5, start2, cstart2,
  1805. 6, end2, cend2);
  1806. len2 = cend2 - cstart2;
  1807. if (cend1 - cstart1 >= len2)
  1808. while (cstart1 <= cend1 - len2)
  1809. {
  1810. i = cstart1;
  1811. j = cstart2;
  1812. while (i < cend1
  1813. && j < cend2
  1814. && (scm_i_string_ref (s1, i)
  1815. == scm_i_string_ref (s2, j)))
  1816. {
  1817. i++;
  1818. j++;
  1819. }
  1820. if (j == cend2)
  1821. {
  1822. scm_remember_upto_here_2 (s1, s2);
  1823. return scm_from_size_t (cstart1);
  1824. }
  1825. cstart1++;
  1826. }
  1827. scm_remember_upto_here_2 (s1, s2);
  1828. return SCM_BOOL_F;
  1829. }
  1830. #undef FUNC_NAME
  1831. /* FIXME::martin: This should definitely get implemented more
  1832. efficiently -- maybe with Knuth-Morris-Pratt, like in the reference
  1833. implementation. */
  1834. SCM_DEFINE (scm_string_contains_ci, "string-contains-ci", 2, 4, 0,
  1835. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  1836. "Does string @var{s1} contain string @var{s2}? Return the index\n"
  1837. "in @var{s1} where @var{s2} occurs as a substring, or false.\n"
  1838. "The optional start/end indices restrict the operation to the\n"
  1839. "indicated substrings. Character comparison is done\n"
  1840. "case-insensitively.")
  1841. #define FUNC_NAME s_scm_string_contains_ci
  1842. {
  1843. size_t cstart1, cend1, cstart2, cend2;
  1844. size_t len2, i, j;
  1845. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  1846. 3, start1, cstart1,
  1847. 4, end1, cend1);
  1848. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  1849. 5, start2, cstart2,
  1850. 6, end2, cend2);
  1851. len2 = cend2 - cstart2;
  1852. if (cend1 - cstart1 >= len2)
  1853. while (cstart1 <= cend1 - len2)
  1854. {
  1855. i = cstart1;
  1856. j = cstart2;
  1857. while (i < cend1
  1858. && j < cend2
  1859. && (uc_tolower (uc_toupper (scm_i_string_ref (s1, i)))
  1860. == uc_tolower (uc_toupper (scm_i_string_ref (s2, j)))))
  1861. {
  1862. i++;
  1863. j++;
  1864. }
  1865. if (j == cend2)
  1866. {
  1867. scm_remember_upto_here_2 (s1, s2);
  1868. return scm_from_size_t (cstart1);
  1869. }
  1870. cstart1++;
  1871. }
  1872. scm_remember_upto_here_2 (s1, s2);
  1873. return SCM_BOOL_F;
  1874. }
  1875. #undef FUNC_NAME
  1876. /* Helper function for the string uppercase conversion functions. */
  1877. static SCM
  1878. string_upcase_x (SCM v, size_t start, size_t end)
  1879. {
  1880. size_t k;
  1881. if (start < end)
  1882. {
  1883. v = scm_i_string_start_writing (v);
  1884. for (k = start; k < end; ++k)
  1885. scm_i_string_set_x (v, k, uc_toupper (scm_i_string_ref (v, k)));
  1886. scm_i_string_stop_writing ();
  1887. scm_remember_upto_here_1 (v);
  1888. }
  1889. return v;
  1890. }
  1891. SCM_DEFINE (scm_substring_upcase_x, "string-upcase!", 1, 2, 0,
  1892. (SCM str, SCM start, SCM end),
  1893. "Destructively upcase every character in @code{str}.\n"
  1894. "\n"
  1895. "@lisp\n"
  1896. "(string-upcase! y)\n"
  1897. "@result{} \"ARRDEFG\"\n"
  1898. "y\n"
  1899. "@result{} \"ARRDEFG\"\n"
  1900. "@end lisp")
  1901. #define FUNC_NAME s_scm_substring_upcase_x
  1902. {
  1903. size_t cstart, cend;
  1904. MY_VALIDATE_SUBSTRING_SPEC (1, str,
  1905. 2, start, cstart,
  1906. 3, end, cend);
  1907. return string_upcase_x (str, cstart, cend);
  1908. }
  1909. #undef FUNC_NAME
  1910. SCM
  1911. scm_string_upcase_x (SCM str)
  1912. {
  1913. return scm_substring_upcase_x (str, SCM_UNDEFINED, SCM_UNDEFINED);
  1914. }
  1915. SCM_DEFINE (scm_substring_upcase, "string-upcase", 1, 2, 0,
  1916. (SCM str, SCM start, SCM end),
  1917. "Upcase every character in @code{str}.")
  1918. #define FUNC_NAME s_scm_substring_upcase
  1919. {
  1920. size_t cstart, cend;
  1921. MY_VALIDATE_SUBSTRING_SPEC (1, str,
  1922. 2, start, cstart,
  1923. 3, end, cend);
  1924. return string_upcase_x (scm_string_copy (str), cstart, cend);
  1925. }
  1926. #undef FUNC_NAME
  1927. SCM
  1928. scm_string_upcase (SCM str)
  1929. {
  1930. return scm_substring_upcase (str, SCM_UNDEFINED, SCM_UNDEFINED);
  1931. }
  1932. /* Helper function for the string lowercase conversion functions.
  1933. * No argument checking is performed. */
  1934. static SCM
  1935. string_downcase_x (SCM v, size_t start, size_t end)
  1936. {
  1937. size_t k;
  1938. if (start < end)
  1939. {
  1940. v = scm_i_string_start_writing (v);
  1941. for (k = start; k < end; ++k)
  1942. scm_i_string_set_x (v, k, uc_tolower (scm_i_string_ref (v, k)));
  1943. scm_i_string_stop_writing ();
  1944. scm_remember_upto_here_1 (v);
  1945. }
  1946. return v;
  1947. }
  1948. SCM_DEFINE (scm_substring_downcase_x, "string-downcase!", 1, 2, 0,
  1949. (SCM str, SCM start, SCM end),
  1950. "Destructively downcase every character in @var{str}.\n"
  1951. "\n"
  1952. "@lisp\n"
  1953. "y\n"
  1954. "@result{} \"ARRDEFG\"\n"
  1955. "(string-downcase! y)\n"
  1956. "@result{} \"arrdefg\"\n"
  1957. "y\n"
  1958. "@result{} \"arrdefg\"\n"
  1959. "@end lisp")
  1960. #define FUNC_NAME s_scm_substring_downcase_x
  1961. {
  1962. size_t cstart, cend;
  1963. MY_VALIDATE_SUBSTRING_SPEC (1, str,
  1964. 2, start, cstart,
  1965. 3, end, cend);
  1966. return string_downcase_x (str, cstart, cend);
  1967. }
  1968. #undef FUNC_NAME
  1969. SCM
  1970. scm_string_downcase_x (SCM str)
  1971. {
  1972. return scm_substring_downcase_x (str, SCM_UNDEFINED, SCM_UNDEFINED);
  1973. }
  1974. SCM_DEFINE (scm_substring_downcase, "string-downcase", 1, 2, 0,
  1975. (SCM str, SCM start, SCM end),
  1976. "Downcase every character in @var{str}.")
  1977. #define FUNC_NAME s_scm_substring_downcase
  1978. {
  1979. size_t cstart, cend;
  1980. MY_VALIDATE_SUBSTRING_SPEC (1, str,
  1981. 2, start, cstart,
  1982. 3, end, cend);
  1983. return string_downcase_x (scm_string_copy (str), cstart, cend);
  1984. }
  1985. #undef FUNC_NAME
  1986. SCM
  1987. scm_string_downcase (SCM str)
  1988. {
  1989. return scm_substring_downcase (str, SCM_UNDEFINED, SCM_UNDEFINED);
  1990. }
  1991. /* Helper function for the string capitalization functions.
  1992. * No argument checking is performed. */
  1993. static SCM
  1994. string_titlecase_x (SCM str, size_t start, size_t end)
  1995. {
  1996. SCM ch;
  1997. size_t i;
  1998. int in_word = 0;
  1999. if (start < end)
  2000. {
  2001. str = scm_i_string_start_writing (str);
  2002. for(i = start; i < end; i++)
  2003. {
  2004. ch = scm_c_make_char (scm_i_string_ref (str, i));
  2005. if (scm_is_true (scm_char_alphabetic_p (ch)))
  2006. {
  2007. if (!in_word)
  2008. {
  2009. scm_i_string_set_x (str, i, uc_totitle (SCM_CHAR (ch)));
  2010. in_word = 1;
  2011. }
  2012. else
  2013. {
  2014. scm_i_string_set_x (str, i, uc_tolower (SCM_CHAR (ch)));
  2015. }
  2016. }
  2017. else
  2018. in_word = 0;
  2019. }
  2020. scm_i_string_stop_writing ();
  2021. scm_remember_upto_here_1 (str);
  2022. }
  2023. return str;
  2024. }
  2025. SCM_DEFINE (scm_string_titlecase_x, "string-titlecase!", 1, 2, 0,
  2026. (SCM str, SCM start, SCM end),
  2027. "Destructively titlecase every first character in a word in\n"
  2028. "@var{str}.")
  2029. #define FUNC_NAME s_scm_string_titlecase_x
  2030. {
  2031. size_t cstart, cend;
  2032. MY_VALIDATE_SUBSTRING_SPEC (1, str,
  2033. 2, start, cstart,
  2034. 3, end, cend);
  2035. return string_titlecase_x (str, cstart, cend);
  2036. }
  2037. #undef FUNC_NAME
  2038. SCM_DEFINE (scm_string_titlecase, "string-titlecase", 1, 2, 0,
  2039. (SCM str, SCM start, SCM end),
  2040. "Titlecase every first character in a word in @var{str}.")
  2041. #define FUNC_NAME s_scm_string_titlecase
  2042. {
  2043. size_t cstart, cend;
  2044. MY_VALIDATE_SUBSTRING_SPEC (1, str,
  2045. 2, start, cstart,
  2046. 3, end, cend);
  2047. return string_titlecase_x (scm_string_copy (str), cstart, cend);
  2048. }
  2049. #undef FUNC_NAME
  2050. SCM_DEFINE (scm_string_capitalize_x, "string-capitalize!", 1, 0, 0,
  2051. (SCM str),
  2052. "Upcase the first character of every word in @var{str}\n"
  2053. "destructively and return @var{str}.\n"
  2054. "\n"
  2055. "@lisp\n"
  2056. "y @result{} \"hello world\"\n"
  2057. "(string-capitalize! y) @result{} \"Hello World\"\n"
  2058. "y @result{} \"Hello World\"\n"
  2059. "@end lisp")
  2060. #define FUNC_NAME s_scm_string_capitalize_x
  2061. {
  2062. return scm_string_titlecase_x (str, SCM_UNDEFINED, SCM_UNDEFINED);
  2063. }
  2064. #undef FUNC_NAME
  2065. SCM_DEFINE (scm_string_capitalize, "string-capitalize", 1, 0, 0,
  2066. (SCM str),
  2067. "Return a freshly allocated string with the characters in\n"
  2068. "@var{str}, where the first character of every word is\n"
  2069. "capitalized.")
  2070. #define FUNC_NAME s_scm_string_capitalize
  2071. {
  2072. return scm_string_capitalize_x (scm_string_copy (str));
  2073. }
  2074. #undef FUNC_NAME
  2075. /* Reverse the portion of @var{str} between str[cstart] (including)
  2076. and str[cend] excluding. */
  2077. static void
  2078. string_reverse_x (SCM str, size_t cstart, size_t cend)
  2079. {
  2080. if (cstart < cend)
  2081. {
  2082. str = scm_i_string_start_writing (str);
  2083. if (cend > 0)
  2084. {
  2085. SCM tmp;
  2086. cend--;
  2087. while (cstart < cend)
  2088. {
  2089. tmp = scm_c_make_char (scm_i_string_ref (str, cstart));
  2090. scm_i_string_set_x (str, cstart, scm_i_string_ref (str, cend));
  2091. scm_i_string_set_x (str, cend, SCM_CHAR (tmp));
  2092. cstart++;
  2093. cend--;
  2094. }
  2095. }
  2096. scm_i_string_stop_writing ();
  2097. }
  2098. }
  2099. SCM_DEFINE (scm_string_reverse, "string-reverse", 1, 2, 0,
  2100. (SCM str, SCM start, SCM end),
  2101. "Reverse the string @var{str}. The optional arguments\n"
  2102. "@var{start} and @var{end} delimit the region of @var{str} to\n"
  2103. "operate on.")
  2104. #define FUNC_NAME s_scm_string_reverse
  2105. {
  2106. size_t cstart, cend;
  2107. SCM result;
  2108. MY_VALIDATE_SUBSTRING_SPEC (1, str,
  2109. 2, start, cstart,
  2110. 3, end, cend);
  2111. result = scm_string_copy (str);
  2112. string_reverse_x (result, cstart, cend);
  2113. scm_remember_upto_here_1 (str);
  2114. return result;
  2115. }
  2116. #undef FUNC_NAME
  2117. SCM_DEFINE (scm_string_reverse_x, "string-reverse!", 1, 2, 0,
  2118. (SCM str, SCM start, SCM end),
  2119. "Reverse the string @var{str} in-place. The optional arguments\n"
  2120. "@var{start} and @var{end} delimit the region of @var{str} to\n"
  2121. "operate on. The return value is unspecified.")
  2122. #define FUNC_NAME s_scm_string_reverse_x
  2123. {
  2124. size_t cstart, cend;
  2125. MY_VALIDATE_SUBSTRING_SPEC (1, str,
  2126. 2, start, cstart,
  2127. 3, end, cend);
  2128. string_reverse_x (str, cstart, cend);
  2129. scm_remember_upto_here_1 (str);
  2130. return SCM_UNSPECIFIED;
  2131. }
  2132. #undef FUNC_NAME
  2133. SCM_DEFINE (scm_string_append_shared, "string-append/shared", 0, 0, 1,
  2134. (SCM rest),
  2135. "Like @code{string-append}, but the result may share memory\n"
  2136. "with the argument strings.")
  2137. #define FUNC_NAME s_scm_string_append_shared
  2138. {
  2139. /* If "rest" contains just one non-empty string, return that.
  2140. If it's entirely empty strings, then return scm_nullstr.
  2141. Otherwise use scm_string_concatenate. */
  2142. SCM ret = scm_nullstr;
  2143. int seen_nonempty = 0;
  2144. SCM l, s;
  2145. SCM_VALIDATE_REST_ARGUMENT (rest);
  2146. for (l = rest; scm_is_pair (l); l = SCM_CDR (l))
  2147. {
  2148. s = SCM_CAR (l);
  2149. if (!scm_is_string (s))
  2150. scm_wrong_type_arg (FUNC_NAME, 0, s);
  2151. if (scm_i_string_length (s) != 0)
  2152. {
  2153. if (seen_nonempty)
  2154. /* two or more non-empty strings, need full concat */
  2155. return scm_string_append (rest);
  2156. seen_nonempty = 1;
  2157. ret = s;
  2158. }
  2159. }
  2160. return ret;
  2161. }
  2162. #undef FUNC_NAME
  2163. SCM_DEFINE (scm_string_concatenate, "string-concatenate", 1, 0, 0,
  2164. (SCM ls),
  2165. "Append the elements of @var{ls} (which must be strings)\n"
  2166. "together into a single string. Guaranteed to return a freshly\n"
  2167. "allocated string.")
  2168. #define FUNC_NAME s_scm_string_concatenate
  2169. {
  2170. SCM_VALIDATE_LIST (SCM_ARG1, ls);
  2171. return scm_string_append (ls);
  2172. }
  2173. #undef FUNC_NAME
  2174. SCM_DEFINE (scm_string_concatenate_reverse, "string-concatenate-reverse", 1, 2, 0,
  2175. (SCM ls, SCM final_string, SCM end),
  2176. "Without optional arguments, this procedure is equivalent to\n"
  2177. "\n"
  2178. "@smalllisp\n"
  2179. "(string-concatenate (reverse ls))\n"
  2180. "@end smalllisp\n"
  2181. "\n"
  2182. "If the optional argument @var{final_string} is specified, it is\n"
  2183. "consed onto the beginning to @var{ls} before performing the\n"
  2184. "list-reverse and string-concatenate operations. If @var{end}\n"
  2185. "is given, only the characters of @var{final_string} up to index\n"
  2186. "@var{end} are used.\n"
  2187. "\n"
  2188. "Guaranteed to return a freshly allocated string.")
  2189. #define FUNC_NAME s_scm_string_concatenate_reverse
  2190. {
  2191. if (!SCM_UNBNDP (end))
  2192. final_string = scm_substring (final_string, SCM_INUM0, end);
  2193. if (!SCM_UNBNDP (final_string))
  2194. ls = scm_cons (final_string, ls);
  2195. return scm_string_concatenate (scm_reverse (ls));
  2196. }
  2197. #undef FUNC_NAME
  2198. SCM_DEFINE (scm_string_concatenate_shared, "string-concatenate/shared", 1, 0, 0,
  2199. (SCM ls),
  2200. "Like @code{string-concatenate}, but the result may share memory\n"
  2201. "with the strings in the list @var{ls}.")
  2202. #define FUNC_NAME s_scm_string_concatenate_shared
  2203. {
  2204. SCM_VALIDATE_LIST (SCM_ARG1, ls);
  2205. return scm_string_append_shared (ls);
  2206. }
  2207. #undef FUNC_NAME
  2208. SCM_DEFINE (scm_string_concatenate_reverse_shared, "string-concatenate-reverse/shared", 1, 2, 0,
  2209. (SCM ls, SCM final_string, SCM end),
  2210. "Like @code{string-concatenate-reverse}, but the result may\n"
  2211. "share memory with the strings in the @var{ls} arguments.")
  2212. #define FUNC_NAME s_scm_string_concatenate_reverse_shared
  2213. {
  2214. /* Just call the non-sharing version. */
  2215. return scm_string_concatenate_reverse (ls, final_string, end);
  2216. }
  2217. #undef FUNC_NAME
  2218. SCM_DEFINE (scm_string_map, "string-map", 2, 2, 0,
  2219. (SCM proc, SCM s, SCM start, SCM end),
  2220. "@var{proc} is a char->char procedure, it is mapped over\n"
  2221. "@var{s}. The order in which the procedure is applied to the\n"
  2222. "string elements is not specified.")
  2223. #define FUNC_NAME s_scm_string_map
  2224. {
  2225. size_t p;
  2226. size_t cstart, cend;
  2227. SCM result;
  2228. SCM_ASSERT (scm_is_true (scm_procedure_p (proc)),
  2229. proc, SCM_ARG1, FUNC_NAME);
  2230. MY_VALIDATE_SUBSTRING_SPEC (2, s,
  2231. 3, start, cstart,
  2232. 4, end, cend);
  2233. result = scm_i_make_string (cend - cstart, NULL, 0);
  2234. p = 0;
  2235. while (cstart < cend)
  2236. {
  2237. SCM ch = scm_call_1 (proc, scm_c_string_ref (s, cstart));
  2238. if (!SCM_CHARP (ch))
  2239. SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc));
  2240. cstart++;
  2241. /* No need to scm_i_string_start_writing (), as the string isn't
  2242. visible to any other thread. */
  2243. scm_i_string_set_x (result, p, SCM_CHAR (ch));
  2244. p++;
  2245. }
  2246. return result;
  2247. }
  2248. #undef FUNC_NAME
  2249. SCM_DEFINE (scm_string_map_x, "string-map!", 2, 2, 0,
  2250. (SCM proc, SCM s, SCM start, SCM end),
  2251. "@var{proc} is a char->char procedure, it is mapped over\n"
  2252. "@var{s}. The order in which the procedure is applied to the\n"
  2253. "string elements is not specified. The string @var{s} is\n"
  2254. "modified in-place, the return value is not specified.")
  2255. #define FUNC_NAME s_scm_string_map_x
  2256. {
  2257. size_t cstart, cend;
  2258. SCM_ASSERT (scm_is_true (scm_procedure_p (proc)),
  2259. proc, SCM_ARG1, FUNC_NAME);
  2260. MY_VALIDATE_SUBSTRING_SPEC (2, s,
  2261. 3, start, cstart,
  2262. 4, end, cend);
  2263. while (cstart < cend)
  2264. {
  2265. SCM ch = scm_call_1 (proc, scm_c_string_ref (s, cstart));
  2266. if (!SCM_CHARP (ch))
  2267. SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (proc));
  2268. s = scm_i_string_start_writing (s);
  2269. scm_i_string_set_x (s, cstart, SCM_CHAR (ch));
  2270. scm_i_string_stop_writing ();
  2271. cstart++;
  2272. }
  2273. return SCM_UNSPECIFIED;
  2274. }
  2275. #undef FUNC_NAME
  2276. SCM_DEFINE (scm_string_fold, "string-fold", 3, 2, 0,
  2277. (SCM kons, SCM knil, SCM s, SCM start, SCM end),
  2278. "Fold @var{kons} over the characters of @var{s}, with @var{knil}\n"
  2279. "as the terminating element, from left to right. @var{kons}\n"
  2280. "must expect two arguments: The actual character and the last\n"
  2281. "result of @var{kons}' application.")
  2282. #define FUNC_NAME s_scm_string_fold
  2283. {
  2284. size_t cstart, cend;
  2285. SCM result;
  2286. SCM_VALIDATE_PROC (1, kons);
  2287. MY_VALIDATE_SUBSTRING_SPEC (3, s,
  2288. 4, start, cstart,
  2289. 5, end, cend);
  2290. result = knil;
  2291. while (cstart < cend)
  2292. {
  2293. result = scm_call_2 (kons, scm_c_make_char (scm_i_string_ref (s, cstart)), result);
  2294. cstart++;
  2295. }
  2296. scm_remember_upto_here_1 (s);
  2297. return result;
  2298. }
  2299. #undef FUNC_NAME
  2300. SCM_DEFINE (scm_string_fold_right, "string-fold-right", 3, 2, 0,
  2301. (SCM kons, SCM knil, SCM s, SCM start, SCM end),
  2302. "Fold @var{kons} over the characters of @var{s}, with @var{knil}\n"
  2303. "as the terminating element, from right to left. @var{kons}\n"
  2304. "must expect two arguments: The actual character and the last\n"
  2305. "result of @var{kons}' application.")
  2306. #define FUNC_NAME s_scm_string_fold_right
  2307. {
  2308. size_t cstart, cend;
  2309. SCM result;
  2310. SCM_VALIDATE_PROC (1, kons);
  2311. MY_VALIDATE_SUBSTRING_SPEC (3, s,
  2312. 4, start, cstart,
  2313. 5, end, cend);
  2314. result = knil;
  2315. while (cstart < cend)
  2316. {
  2317. result = scm_call_2 (kons, scm_c_make_char (scm_i_string_ref (s, cend-1)), result);
  2318. cend--;
  2319. }
  2320. scm_remember_upto_here_1 (s);
  2321. return result;
  2322. }
  2323. #undef FUNC_NAME
  2324. SCM_DEFINE (scm_string_unfold, "string-unfold", 4, 2, 0,
  2325. (SCM p, SCM f, SCM g, SCM seed, SCM base, SCM make_final),
  2326. "@itemize @bullet\n"
  2327. "@item @var{g} is used to generate a series of @emph{seed}\n"
  2328. "values from the initial @var{seed}: @var{seed}, (@var{g}\n"
  2329. "@var{seed}), (@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}),\n"
  2330. "@dots{}\n"
  2331. "@item @var{p} tells us when to stop -- when it returns true\n"
  2332. "when applied to one of these seed values.\n"
  2333. "@item @var{f} maps each seed value to the corresponding\n"
  2334. "character in the result string. These chars are assembled\n"
  2335. "into the string in a left-to-right order.\n"
  2336. "@item @var{base} is the optional initial/leftmost portion\n"
  2337. "of the constructed string; it default to the empty\n"
  2338. "string.\n"
  2339. "@item @var{make_final} is applied to the terminal seed\n"
  2340. "value (on which @var{p} returns true) to produce\n"
  2341. "the final/rightmost portion of the constructed string.\n"
  2342. "It defaults to @code{(lambda (x) "")}.\n"
  2343. "@end itemize")
  2344. #define FUNC_NAME s_scm_string_unfold
  2345. {
  2346. SCM res, ans;
  2347. SCM_VALIDATE_PROC (1, p);
  2348. SCM_VALIDATE_PROC (2, f);
  2349. SCM_VALIDATE_PROC (3, g);
  2350. if (!SCM_UNBNDP (base))
  2351. {
  2352. SCM_VALIDATE_STRING (5, base);
  2353. ans = base;
  2354. }
  2355. else
  2356. ans = scm_i_make_string (0, NULL, 0);
  2357. if (!SCM_UNBNDP (make_final))
  2358. SCM_VALIDATE_PROC (6, make_final);
  2359. res = scm_call_1 (p, seed);
  2360. while (scm_is_false (res))
  2361. {
  2362. SCM str;
  2363. size_t i = 0;
  2364. SCM ch = scm_call_1 (f, seed);
  2365. if (!SCM_CHARP (ch))
  2366. SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f));
  2367. str = scm_i_make_string (1, NULL, 0);
  2368. /* No need to scm_i_string_start_writing (), as the string isn't
  2369. visible to any other thread. */
  2370. scm_i_string_set_x (str, i, SCM_CHAR (ch));
  2371. i++;
  2372. ans = scm_string_append (scm_list_2 (ans, str));
  2373. seed = scm_call_1 (g, seed);
  2374. res = scm_call_1 (p, seed);
  2375. }
  2376. if (!SCM_UNBNDP (make_final))
  2377. {
  2378. res = scm_call_1 (make_final, seed);
  2379. return scm_string_append (scm_list_2 (ans, res));
  2380. }
  2381. else
  2382. return ans;
  2383. }
  2384. #undef FUNC_NAME
  2385. SCM_DEFINE (scm_string_unfold_right, "string-unfold-right", 4, 2, 0,
  2386. (SCM p, SCM f, SCM g, SCM seed, SCM base, SCM make_final),
  2387. "@itemize @bullet\n"
  2388. "@item @var{g} is used to generate a series of @emph{seed}\n"
  2389. "values from the initial @var{seed}: @var{seed}, (@var{g}\n"
  2390. "@var{seed}), (@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}),\n"
  2391. "@dots{}\n"
  2392. "@item @var{p} tells us when to stop -- when it returns true\n"
  2393. "when applied to one of these seed values.\n"
  2394. "@item @var{f} maps each seed value to the corresponding\n"
  2395. "character in the result string. These chars are assembled\n"
  2396. "into the string in a right-to-left order.\n"
  2397. "@item @var{base} is the optional initial/rightmost portion\n"
  2398. "of the constructed string; it default to the empty\n"
  2399. "string.\n"
  2400. "@item @var{make_final} is applied to the terminal seed\n"
  2401. "value (on which @var{p} returns true) to produce\n"
  2402. "the final/leftmost portion of the constructed string.\n"
  2403. "It defaults to @code{(lambda (x) "")}.\n"
  2404. "@end itemize")
  2405. #define FUNC_NAME s_scm_string_unfold_right
  2406. {
  2407. SCM res, ans;
  2408. SCM_VALIDATE_PROC (1, p);
  2409. SCM_VALIDATE_PROC (2, f);
  2410. SCM_VALIDATE_PROC (3, g);
  2411. if (!SCM_UNBNDP (base))
  2412. {
  2413. SCM_VALIDATE_STRING (5, base);
  2414. ans = base;
  2415. }
  2416. else
  2417. ans = scm_i_make_string (0, NULL, 0);
  2418. if (!SCM_UNBNDP (make_final))
  2419. SCM_VALIDATE_PROC (6, make_final);
  2420. res = scm_call_1 (p, seed);
  2421. while (scm_is_false (res))
  2422. {
  2423. SCM str;
  2424. size_t i = 0;
  2425. SCM ch = scm_call_1 (f, seed);
  2426. if (!SCM_CHARP (ch))
  2427. SCM_MISC_ERROR ("procedure ~S returned non-char", scm_list_1 (f));
  2428. str = scm_i_make_string (1, NULL, 0);
  2429. /* No need to scm_i_string_start_writing (), as the string isn't
  2430. visible to any other thread. */
  2431. scm_i_string_set_x (str, i, SCM_CHAR (ch));
  2432. i++;
  2433. ans = scm_string_append (scm_list_2 (str, ans));
  2434. seed = scm_call_1 (g, seed);
  2435. res = scm_call_1 (p, seed);
  2436. }
  2437. if (!SCM_UNBNDP (make_final))
  2438. {
  2439. res = scm_call_1 (make_final, seed);
  2440. return scm_string_append (scm_list_2 (res, ans));
  2441. }
  2442. else
  2443. return ans;
  2444. }
  2445. #undef FUNC_NAME
  2446. SCM_DEFINE (scm_string_for_each, "string-for-each", 2, 2, 0,
  2447. (SCM proc, SCM s, SCM start, SCM end),
  2448. "@var{proc} is mapped over @var{s} in left-to-right order. The\n"
  2449. "return value is not specified.")
  2450. #define FUNC_NAME s_scm_string_for_each
  2451. {
  2452. size_t cstart, cend;
  2453. SCM_ASSERT (scm_is_true (scm_procedure_p (proc)),
  2454. proc, SCM_ARG1, FUNC_NAME);
  2455. MY_VALIDATE_SUBSTRING_SPEC (2, s,
  2456. 3, start, cstart,
  2457. 4, end, cend);
  2458. while (cstart < cend)
  2459. {
  2460. scm_call_1 (proc, scm_c_make_char (scm_i_string_ref (s, cstart)));
  2461. cstart++;
  2462. }
  2463. scm_remember_upto_here_1 (s);
  2464. return SCM_UNSPECIFIED;
  2465. }
  2466. #undef FUNC_NAME
  2467. SCM_DEFINE (scm_string_for_each_index, "string-for-each-index", 2, 2, 0,
  2468. (SCM proc, SCM s, SCM start, SCM end),
  2469. "Call @code{(@var{proc} i)} for each index i in @var{s}, from\n"
  2470. "left to right.\n"
  2471. "\n"
  2472. "For example, to change characters to alternately upper and\n"
  2473. "lower case,\n"
  2474. "\n"
  2475. "@example\n"
  2476. "(define str (string-copy \"studly\"))\n"
  2477. "(string-for-each-index\n"
  2478. " (lambda (i)\n"
  2479. " (string-set! str i\n"
  2480. " ((if (even? i) char-upcase char-downcase)\n"
  2481. " (string-ref str i))))\n"
  2482. " str)\n"
  2483. "str @result{} \"StUdLy\"\n"
  2484. "@end example")
  2485. #define FUNC_NAME s_scm_string_for_each_index
  2486. {
  2487. size_t cstart, cend;
  2488. SCM_ASSERT (scm_is_true (scm_procedure_p (proc)),
  2489. proc, SCM_ARG1, FUNC_NAME);
  2490. MY_VALIDATE_SUBSTRING_SPEC (2, s,
  2491. 3, start, cstart,
  2492. 4, end, cend);
  2493. while (cstart < cend)
  2494. {
  2495. scm_call_1 (proc, scm_from_size_t (cstart));
  2496. cstart++;
  2497. }
  2498. scm_remember_upto_here_1 (s);
  2499. return SCM_UNSPECIFIED;
  2500. }
  2501. #undef FUNC_NAME
  2502. SCM_DEFINE (scm_xsubstring, "xsubstring", 2, 3, 0,
  2503. (SCM s, SCM from, SCM to, SCM start, SCM end),
  2504. "This is the @emph{extended substring} procedure that implements\n"
  2505. "replicated copying of a substring of some string.\n"
  2506. "\n"
  2507. "@var{s} is a string, @var{start} and @var{end} are optional\n"
  2508. "arguments that demarcate a substring of @var{s}, defaulting to\n"
  2509. "0 and the length of @var{s}. Replicate this substring up and\n"
  2510. "down index space, in both the positive and negative directions.\n"
  2511. "@code{xsubstring} returns the substring of this string\n"
  2512. "beginning at index @var{from}, and ending at @var{to}, which\n"
  2513. "defaults to @var{from} + (@var{end} - @var{start}).")
  2514. #define FUNC_NAME s_scm_xsubstring
  2515. {
  2516. size_t p;
  2517. size_t cstart, cend;
  2518. int cfrom, cto;
  2519. SCM result;
  2520. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  2521. 4, start, cstart,
  2522. 5, end, cend);
  2523. cfrom = scm_to_int (from);
  2524. if (SCM_UNBNDP (to))
  2525. cto = cfrom + (cend - cstart);
  2526. else
  2527. cto = scm_to_int (to);
  2528. if (cstart == cend && cfrom != cto)
  2529. SCM_MISC_ERROR ("start and end indices must not be equal", SCM_EOL);
  2530. result = scm_i_make_string (cto - cfrom, NULL, 0);
  2531. p = 0;
  2532. while (cfrom < cto)
  2533. {
  2534. size_t t = ((cfrom < 0) ? -cfrom : cfrom) % (cend - cstart);
  2535. if (cfrom < 0)
  2536. scm_i_string_set_x (result, p,
  2537. scm_i_string_ref (s, (cend - cstart) - t));
  2538. else
  2539. scm_i_string_set_x (result, p, scm_i_string_ref (s, t));
  2540. cfrom++;
  2541. p++;
  2542. }
  2543. scm_remember_upto_here_1 (s);
  2544. return result;
  2545. }
  2546. #undef FUNC_NAME
  2547. SCM_DEFINE (scm_string_xcopy_x, "string-xcopy!", 4, 3, 0,
  2548. (SCM target, SCM tstart, SCM s, SCM sfrom, SCM sto, SCM start, SCM end),
  2549. "Exactly the same as @code{xsubstring}, but the extracted text\n"
  2550. "is written into the string @var{target} starting at index\n"
  2551. "@var{tstart}. The operation is not defined if @code{(eq?\n"
  2552. "@var{target} @var{s})} or these arguments share storage -- you\n"
  2553. "cannot copy a string on top of itself.")
  2554. #define FUNC_NAME s_scm_string_xcopy_x
  2555. {
  2556. size_t p;
  2557. size_t ctstart, cstart, cend;
  2558. int csfrom, csto;
  2559. SCM dummy = SCM_UNDEFINED;
  2560. size_t cdummy;
  2561. MY_VALIDATE_SUBSTRING_SPEC (1, target,
  2562. 2, tstart, ctstart,
  2563. 2, dummy, cdummy);
  2564. MY_VALIDATE_SUBSTRING_SPEC (3, s,
  2565. 6, start, cstart,
  2566. 7, end, cend);
  2567. csfrom = scm_to_int (sfrom);
  2568. if (SCM_UNBNDP (sto))
  2569. csto = csfrom + (cend - cstart);
  2570. else
  2571. csto = scm_to_int (sto);
  2572. if (csfrom < csto)
  2573. {
  2574. if (cstart == cend)
  2575. SCM_MISC_ERROR ("start and end indices must not be equal", SCM_EOL);
  2576. SCM_ASSERT_RANGE (1, tstart,
  2577. ctstart + (csto - csfrom) <= scm_i_string_length (target));
  2578. p = 0;
  2579. target = scm_i_string_start_writing (target);
  2580. while (csfrom < csto)
  2581. {
  2582. size_t t = ((csfrom < 0) ? -csfrom : csfrom) % (cend - cstart);
  2583. if (csfrom < 0)
  2584. scm_i_string_set_x (target, p + cstart, scm_i_string_ref (s, (cend - cstart) - t));
  2585. else
  2586. scm_i_string_set_x (target, p + cstart, scm_i_string_ref (s, t));
  2587. csfrom++;
  2588. p++;
  2589. }
  2590. scm_i_string_stop_writing ();
  2591. scm_remember_upto_here_2 (target, s);
  2592. }
  2593. return SCM_UNSPECIFIED;
  2594. }
  2595. #undef FUNC_NAME
  2596. SCM_DEFINE (scm_string_replace, "string-replace", 2, 4, 0,
  2597. (SCM s1, SCM s2, SCM start1, SCM end1, SCM start2, SCM end2),
  2598. "Return the string @var{s1}, but with the characters\n"
  2599. "@var{start1} @dots{} @var{end1} replaced by the characters\n"
  2600. "@var{start2} @dots{} @var{end2} from @var{s2}.")
  2601. #define FUNC_NAME s_scm_string_replace
  2602. {
  2603. size_t cstart1, cend1, cstart2, cend2;
  2604. SCM result;
  2605. MY_VALIDATE_SUBSTRING_SPEC (1, s1,
  2606. 3, start1, cstart1,
  2607. 4, end1, cend1);
  2608. MY_VALIDATE_SUBSTRING_SPEC (2, s2,
  2609. 5, start2, cstart2,
  2610. 6, end2, cend2);
  2611. return (scm_string_append
  2612. (scm_list_3 (scm_i_substring (s1, 0, cstart1),
  2613. scm_i_substring (s2, cstart2, cend2),
  2614. scm_i_substring (s1, cend1, scm_i_string_length (s1)))));
  2615. return result;
  2616. }
  2617. #undef FUNC_NAME
  2618. SCM_DEFINE (scm_string_tokenize, "string-tokenize", 1, 3, 0,
  2619. (SCM s, SCM token_set, SCM start, SCM end),
  2620. "Split the string @var{s} into a list of substrings, where each\n"
  2621. "substring is a maximal non-empty contiguous sequence of\n"
  2622. "characters from the character set @var{token_set}, which\n"
  2623. "defaults to @code{char-set:graphic}.\n"
  2624. "If @var{start} or @var{end} indices are provided, they restrict\n"
  2625. "@code{string-tokenize} to operating on the indicated substring\n"
  2626. "of @var{s}.")
  2627. #define FUNC_NAME s_scm_string_tokenize
  2628. {
  2629. size_t cstart, cend;
  2630. SCM result = SCM_EOL;
  2631. MY_VALIDATE_SUBSTRING_SPEC (1, s,
  2632. 3, start, cstart,
  2633. 4, end, cend);
  2634. if (SCM_UNBNDP (token_set))
  2635. token_set = scm_char_set_graphic;
  2636. if (SCM_CHARSETP (token_set))
  2637. {
  2638. size_t idx;
  2639. while (cstart < cend)
  2640. {
  2641. while (cstart < cend)
  2642. {
  2643. if (REF_IN_CHARSET (s, cend-1, token_set))
  2644. break;
  2645. cend--;
  2646. }
  2647. if (cstart >= cend)
  2648. break;
  2649. idx = cend;
  2650. while (cstart < cend)
  2651. {
  2652. if (!REF_IN_CHARSET (s, cend-1, token_set))
  2653. break;
  2654. cend--;
  2655. }
  2656. result = scm_cons (scm_i_substring (s, cend, idx), result);
  2657. }
  2658. }
  2659. else
  2660. SCM_WRONG_TYPE_ARG (2, token_set);
  2661. scm_remember_upto_here_1 (s);
  2662. return result;
  2663. }
  2664. #undef FUNC_NAME
  2665. SCM_DEFINE (scm_string_split, "string-split", 2, 0, 0,
  2666. (SCM str, SCM char_pred),
  2667. "Split the string @var{str} into a list of the substrings delimited\n"
  2668. "by appearances of characters that\n"
  2669. "\n"
  2670. "@itemize @bullet\n"
  2671. "@item\n"
  2672. "equal @var{char_pred}, if it is a character,\n"
  2673. "\n"
  2674. "@item\n"
  2675. "satisfy the predicate @var{char_pred}, if it is a procedure,\n"
  2676. "\n"
  2677. "@item\n"
  2678. "are in the set @var{char_pred}, if it is a character set.\n"
  2679. "@end itemize\n\n"
  2680. "Note that an empty substring between separator characters\n"
  2681. "will result in an empty string in the result list.\n"
  2682. "\n"
  2683. "@lisp\n"
  2684. "(string-split \"root:x:0:0:root:/root:/bin/bash\" #\\:)\n"
  2685. "@result{}\n"
  2686. "(\"root\" \"x\" \"0\" \"0\" \"root\" \"/root\" \"/bin/bash\")\n"
  2687. "\n"
  2688. "(string-split \"::\" #\\:)\n"
  2689. "@result{}\n"
  2690. "(\"\" \"\" \"\")\n"
  2691. "\n"
  2692. "(string-split \"\" #\\:)\n"
  2693. "@result{}\n"
  2694. "(\"\")\n"
  2695. "@end lisp")
  2696. #define FUNC_NAME s_scm_string_split
  2697. {
  2698. SCM res = SCM_EOL;
  2699. SCM_VALIDATE_STRING (1, str);
  2700. if (SCM_CHARP (char_pred))
  2701. {
  2702. long idx, last_idx;
  2703. int narrow;
  2704. /* This is explicit wide/narrow logic (instead of using
  2705. scm_i_string_ref) is a speed optimization. */
  2706. idx = scm_i_string_length (str);
  2707. narrow = scm_i_is_narrow_string (str);
  2708. if (narrow)
  2709. {
  2710. const char *buf = scm_i_string_chars (str);
  2711. while (idx >= 0)
  2712. {
  2713. last_idx = idx;
  2714. while (idx > 0 && buf[idx-1] != (char) SCM_CHAR(char_pred))
  2715. idx--;
  2716. if (idx >= 0)
  2717. {
  2718. res = scm_cons (scm_i_substring (str, idx, last_idx), res);
  2719. idx--;
  2720. }
  2721. }
  2722. }
  2723. else
  2724. {
  2725. const scm_t_wchar *buf = scm_i_string_wide_chars (str);
  2726. while (idx >= 0)
  2727. {
  2728. last_idx = idx;
  2729. while (idx > 0 && buf[idx-1] != SCM_CHAR(char_pred))
  2730. idx--;
  2731. if (idx >= 0)
  2732. {
  2733. res = scm_cons (scm_i_substring (str, idx, last_idx), res);
  2734. idx--;
  2735. }
  2736. }
  2737. }
  2738. }
  2739. else
  2740. {
  2741. SCM sidx, slast_idx;
  2742. if (!SCM_CHARSETP (char_pred))
  2743. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  2744. char_pred, SCM_ARG2, FUNC_NAME);
  2745. /* Supporting predicates and character sets involves handling SCM
  2746. values so there is less chance to optimize. */
  2747. slast_idx = scm_string_length (str);
  2748. for (;;)
  2749. {
  2750. sidx = scm_string_index_right (str, char_pred, SCM_INUM0, slast_idx);
  2751. if (scm_is_false (sidx))
  2752. break;
  2753. res = scm_cons (scm_substring (str, scm_oneplus (sidx), slast_idx), res);
  2754. slast_idx = sidx;
  2755. }
  2756. res = scm_cons (scm_substring (str, SCM_INUM0, slast_idx), res);
  2757. }
  2758. scm_remember_upto_here_1 (str);
  2759. return res;
  2760. }
  2761. #undef FUNC_NAME
  2762. SCM_DEFINE (scm_string_filter, "string-filter", 2, 2, 0,
  2763. (SCM char_pred, SCM s, SCM start, SCM end),
  2764. "Filter the string @var{s}, retaining only those characters\n"
  2765. "which satisfy @var{char_pred}.\n"
  2766. "\n"
  2767. "If @var{char_pred} is a procedure, it is applied to each\n"
  2768. "character as a predicate, if it is a character, it is tested\n"
  2769. "for equality and if it is a character set, it is tested for\n"
  2770. "membership.")
  2771. #define FUNC_NAME s_scm_string_filter
  2772. {
  2773. size_t cstart, cend;
  2774. SCM result;
  2775. size_t idx;
  2776. MY_VALIDATE_SUBSTRING_SPEC (2, s,
  2777. 3, start, cstart,
  2778. 4, end, cend);
  2779. /* The explicit loops below stripping leading and trailing non-matches
  2780. mean we can return a substring if those are the only deletions, making
  2781. string-filter as efficient as string-trim-both in that case. */
  2782. if (SCM_CHARP (char_pred))
  2783. {
  2784. size_t count;
  2785. /* strip leading non-matches by incrementing cstart */
  2786. while (cstart < cend && scm_i_string_ref (s, cstart) != SCM_CHAR (char_pred))
  2787. cstart++;
  2788. /* strip trailing non-matches by decrementing cend */
  2789. while (cend > cstart && scm_i_string_ref (s, cend-1) != SCM_CHAR (char_pred))
  2790. cend--;
  2791. /* count chars to keep */
  2792. count = 0;
  2793. for (idx = cstart; idx < cend; idx++)
  2794. if (scm_i_string_ref (s, idx) == SCM_CHAR (char_pred))
  2795. count++;
  2796. if (count == cend - cstart)
  2797. {
  2798. /* whole of cstart to cend is to be kept, return a copy-on-write
  2799. substring */
  2800. result_substring:
  2801. result = scm_i_substring (s, cstart, cend);
  2802. }
  2803. else
  2804. result = scm_c_make_string (count, char_pred);
  2805. }
  2806. else if (SCM_CHARSETP (char_pred))
  2807. {
  2808. size_t count;
  2809. /* strip leading non-matches by incrementing cstart */
  2810. while (cstart < cend && ! REF_IN_CHARSET (s, cstart, char_pred))
  2811. cstart++;
  2812. /* strip trailing non-matches by decrementing cend */
  2813. while (cend > cstart && ! REF_IN_CHARSET (s, cend-1, char_pred))
  2814. cend--;
  2815. /* count chars to be kept */
  2816. count = 0;
  2817. for (idx = cstart; idx < cend; idx++)
  2818. if (REF_IN_CHARSET (s, idx, char_pred))
  2819. count++;
  2820. /* if whole of start to end kept then return substring */
  2821. if (count == cend - cstart)
  2822. goto result_substring;
  2823. else
  2824. {
  2825. size_t dst = 0;
  2826. result = scm_i_make_string (count, NULL, 0);
  2827. /* No need to scm_i_string_start_writing (), as the string isn't
  2828. visible to any other thread. */
  2829. /* decrement "count" in this loop as well as using idx, so that if
  2830. another thread is simultaneously changing "s" there's no chance
  2831. it'll make us copy more than count characters */
  2832. for (idx = cstart; idx < cend && count != 0; idx++)
  2833. {
  2834. if (REF_IN_CHARSET (s, idx, char_pred))
  2835. {
  2836. scm_i_string_set_x (result, dst, scm_i_string_ref (s, idx));
  2837. dst ++;
  2838. count--;
  2839. }
  2840. }
  2841. }
  2842. }
  2843. else
  2844. {
  2845. SCM ls = SCM_EOL;
  2846. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  2847. char_pred, SCM_ARG1, FUNC_NAME);
  2848. idx = cstart;
  2849. while (idx < cend)
  2850. {
  2851. SCM res, ch;
  2852. ch = scm_c_make_char (scm_i_string_ref (s, idx));
  2853. res = scm_call_1 (char_pred, ch);
  2854. if (scm_is_true (res))
  2855. ls = scm_cons (ch, ls);
  2856. idx++;
  2857. }
  2858. result = scm_reverse_list_to_string (ls);
  2859. }
  2860. scm_remember_upto_here_1 (s);
  2861. return result;
  2862. }
  2863. #undef FUNC_NAME
  2864. SCM_DEFINE (scm_string_delete, "string-delete", 2, 2, 0,
  2865. (SCM char_pred, SCM s, SCM start, SCM end),
  2866. "Delete characters satisfying @var{char_pred} from @var{s}.\n"
  2867. "\n"
  2868. "If @var{char_pred} is a procedure, it is applied to each\n"
  2869. "character as a predicate, if it is a character, it is tested\n"
  2870. "for equality and if it is a character set, it is tested for\n"
  2871. "membership.")
  2872. #define FUNC_NAME s_scm_string_delete
  2873. {
  2874. size_t cstart, cend;
  2875. SCM result;
  2876. size_t idx;
  2877. MY_VALIDATE_SUBSTRING_SPEC (2, s,
  2878. 3, start, cstart,
  2879. 4, end, cend);
  2880. /* The explicit loops below stripping leading and trailing matches mean we
  2881. can return a substring if those are the only deletions, making
  2882. string-delete as efficient as string-trim-both in that case. */
  2883. if (SCM_CHARP (char_pred))
  2884. {
  2885. size_t count;
  2886. /* strip leading matches by incrementing cstart */
  2887. while (cstart < cend && scm_i_string_ref (s, cstart) == SCM_CHAR(char_pred))
  2888. cstart++;
  2889. /* strip trailing matches by decrementing cend */
  2890. while (cend > cstart && scm_i_string_ref (s, cend-1) == SCM_CHAR (char_pred))
  2891. cend--;
  2892. /* count chars to be kept */
  2893. count = 0;
  2894. for (idx = cstart; idx < cend; idx++)
  2895. if (scm_i_string_ref (s, idx) != SCM_CHAR (char_pred))
  2896. count++;
  2897. if (count == cend - cstart)
  2898. {
  2899. /* whole of cstart to cend is to be kept, return a copy-on-write
  2900. substring */
  2901. result_substring:
  2902. result = scm_i_substring (s, cstart, cend);
  2903. }
  2904. else
  2905. {
  2906. int i = 0;
  2907. /* new string for retained portion */
  2908. result = scm_i_make_string (count, NULL, 0);
  2909. /* No need to scm_i_string_start_writing (), as the string isn't
  2910. visible to any other thread. */
  2911. /* decrement "count" in this loop as well as using idx, so that if
  2912. another thread is simultaneously changing "s" there's no chance
  2913. it'll make us copy more than count characters */
  2914. for (idx = cstart; idx < cend && count != 0; idx++)
  2915. {
  2916. scm_t_wchar c = scm_i_string_ref (s, idx);
  2917. if (c != SCM_CHAR (char_pred))
  2918. {
  2919. scm_i_string_set_x (result, i, c);
  2920. i++;
  2921. count--;
  2922. }
  2923. }
  2924. }
  2925. }
  2926. else if (SCM_CHARSETP (char_pred))
  2927. {
  2928. size_t count;
  2929. /* strip leading matches by incrementing cstart */
  2930. while (cstart < cend && REF_IN_CHARSET (s, cstart, char_pred))
  2931. cstart++;
  2932. /* strip trailing matches by decrementing cend */
  2933. while (cend > cstart && REF_IN_CHARSET (s, cend-1, char_pred))
  2934. cend--;
  2935. /* count chars to be kept */
  2936. count = 0;
  2937. for (idx = cstart; idx < cend; idx++)
  2938. if (!REF_IN_CHARSET (s, idx, char_pred))
  2939. count++;
  2940. if (count == cend - cstart)
  2941. goto result_substring;
  2942. else
  2943. {
  2944. size_t i = 0;
  2945. /* new string for retained portion */
  2946. result = scm_i_make_string (count, NULL, 0);
  2947. /* No need to scm_i_string_start_writing (), as the string isn't
  2948. visible to any other thread. */
  2949. /* decrement "count" in this loop as well as using idx, so that if
  2950. another thread is simultaneously changing "s" there's no chance
  2951. it'll make us copy more than count characters */
  2952. for (idx = cstart; idx < cend && count != 0; idx++)
  2953. {
  2954. if (!REF_IN_CHARSET (s, idx, char_pred))
  2955. {
  2956. scm_i_string_set_x (result, i, scm_i_string_ref (s, idx));
  2957. i++;
  2958. count--;
  2959. }
  2960. }
  2961. }
  2962. }
  2963. else
  2964. {
  2965. SCM ls = SCM_EOL;
  2966. SCM_ASSERT (scm_is_true (scm_procedure_p (char_pred)),
  2967. char_pred, SCM_ARG1, FUNC_NAME);
  2968. idx = cstart;
  2969. while (idx < cend)
  2970. {
  2971. SCM res, ch = scm_c_make_char (scm_i_string_ref (s, idx));
  2972. res = scm_call_1 (char_pred, ch);
  2973. if (scm_is_false (res))
  2974. ls = scm_cons (ch, ls);
  2975. idx++;
  2976. }
  2977. result = scm_reverse_list_to_string (ls);
  2978. }
  2979. scm_remember_upto_here_1 (s);
  2980. return result;
  2981. }
  2982. #undef FUNC_NAME
  2983. void
  2984. scm_init_srfi_13 (void)
  2985. {
  2986. #include "srfi-13.x"
  2987. }
  2988. /* End of srfi-13.c. */