PageRenderTime 75ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/V_33_62/pfe-33/pfe/core-sub.c

#
C | 1795 lines | 1404 code | 126 blank | 265 comment | 233 complexity | df90083c16091893ac320d98d06b44d7 MD5 | raw file
Possible License(s): Zlib, LGPL-2.0, AGPL-3.0, LGPL-2.1
  1. /**
  2. * -- Subroutines for the Core Forth-System
  3. *
  4. * Copyright (C) Tektronix, Inc. 1998 - 2001.
  5. * Copyright (C) 2005 - 2006 Guido U. Draheim <guidod@gmx.de>
  6. *
  7. * @see GNU LGPL
  8. * @author Guido U. Draheim (modified by $Author: guidod $)
  9. * @version $Revision: 1.3 $
  10. * (modified $Date: 2006-08-11 22:56:04 $)
  11. *
  12. * @description
  13. * Subroutines for the Forth Core System - especially the
  14. * general input/output routines like ACCEPT/QUERY/WORD/PARSE
  15. * and converters like UD.DR and >NUMBER
  16. */
  17. /*@{*/
  18. #if defined(__version_control__) && defined(__GNUC__)
  19. static char* id __attribute__((unused)) =
  20. "@(#) $Id: core-sub.c,v 1.3 2006-08-11 22:56:04 guidod Exp $";
  21. #endif
  22. #define _P4_SOURCE 1
  23. #include <pfe/pfe-base.h>
  24. #include <pfe/def-limits.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <stdarg.h>
  28. #include <math.h>
  29. #include <limits.h>
  30. #include <errno.h>
  31. #include <pfe/os-string.h>
  32. #include <pfe/os-ctype.h>
  33. #ifdef PFE_HAVE_UNISTD_H
  34. #include <unistd.h> /* access() if available */
  35. #endif
  36. #if defined PFE_HAVE_PWD_H
  37. #include <pwd.h> /* to resolve ~user/path */
  38. #endif
  39. #include <pfe/double-sub.h>
  40. #include <pfe/block-sub.h>
  41. #include <pfe/file-sub.h>
  42. #include <pfe/term-sub.h>
  43. #include <pfe/lined.h>
  44. #include <pfe/_missing.h>
  45. #include <pfe/logging.h>
  46. #define ___ {
  47. #define ____ }
  48. /***********************************************************************/
  49. /* removed this one from general def-types */
  50. #define SPAN p4_SPAN
  51. /**
  52. * return cell-aligned address
  53. */
  54. _export P4_GCC_CONST p4cell
  55. p4_aligned (p4cell n)
  56. {
  57. while (!P4_ALIGNED (n))
  58. n++;
  59. return n;
  60. }
  61. /* *********************************************************************
  62. * strings
  63. */
  64. /** _strpush_ ( zstr* -- S: str* str# )
  65. * push a C-string onto the SP runtime-stack, as if => S" string" was used
  66. : _strpush_ s! _strlen_ s! ;
  67. */
  68. _export void
  69. p4_strpush (const char *s)
  70. {
  71. if (s) {
  72. *--SP = (p4cell)s; *--SP = p4_strlen (s);
  73. } else {
  74. *--SP = 0; *--SP = 0;
  75. }
  76. }
  77. /** _pocket_ ( -- str* )
  78. * return the next pocket for interactive string input.
  79. : _pocket_ _pockets@_ _pocket@_ th _pocket@_ 1+ _pockets#_ mod to _pocket@_ ;
  80. */
  81. _export P4_GCC_MALLOC void*
  82. p4_pocket (void)
  83. {
  84. register void *p = PFE.pocket->buffer;
  85. if (++ PFE.pocket >= PFE.pockets_top) PFE.pocket = PFE.pockets_ptr;
  86. return p;
  87. }
  88. /** _-trailing_ ( str* str# -- str#' )
  89. * chop off trailing spaces for the stringbuffer. returns the new length,
  90. * so for an internal counted string, use
  91. <x> dup count _-trailing_ c!
  92. : _-trailing_ begin dup while
  93. 2dup + c@ bl <> if nip exit then
  94. 1- repeat nip ;
  95. */
  96. _export P4_GCC_WARN_UNUSED_RESULT int
  97. p4_dash_trailing (p4_char_t *s, int n)
  98. {
  99. while (n > 0 && p4_isspace (s[n - 1]))
  100. {
  101. n--;
  102. }
  103. return n;
  104. }
  105. /** _lower_ ( str* str# -- )
  106. * _tolower_ applied to a stringbuffer
  107. : _lower_ 0 do dup c@ _tolower_ over c! 1+ loop drop ;
  108. */
  109. _export void
  110. p4_lower (p4_char_t *p, int n)
  111. {
  112. while (--n >= 0)
  113. {
  114. *p = (p4_char_t) tolower ((char) *p);
  115. p++;
  116. }
  117. }
  118. /** _upper_ ( str* str# -- )
  119. * _toupper_ applied to a stringbuffer
  120. : _upper_ 0 do dup c@ _toupper_ over c! 1+ loop drop ;
  121. */
  122. _export void
  123. p4_upper (p4_char_t *p, int n)
  124. {
  125. while (--n >= 0)
  126. {
  127. *p = (p4_char_t) toupper ((char) *p);
  128. p++;
  129. }
  130. }
  131. /** _zplaced_ ( str* str# dst* max# -- dst* ) [alias] _store_c_string_
  132. * copy stringbuffer into a field as a zero-terminated string.
  133. : _zsplaced_ rot 2dup > if drop 1- else nip then _zplace_ ;
  134. */
  135. _export char*
  136. p4_store_c_string (const p4_char_t *src, int n, char *dst, int max)
  137. {
  138. /* RENAME: p4_zplaced */
  139. if (n >= max)
  140. n = max - 1;
  141. p4_memcpy (dst, src, n);
  142. dst[n] = '\0';
  143. return dst;
  144. }
  145. /** _pocket_zplaced ( str* str# -- pocket* ) [alias] _pocket_c_string_
  146. * store a string-span as a zero-terminated string into another pocket-pad
  147. : _pocket_zplaced _pocket_ _/pocket_ _zplaced_ ;
  148. */
  149. _export P4_GCC_MALLOC char*
  150. p4_pocket_c_string (const p4_char_t* src, int n)
  151. {
  152. /* RENAME: p4_pocket_zplace */ /* REQUIRE: p4_pocket_place */
  153. return p4_store_c_string (src, n, p4_pocket (), P4_POCKET_SIZE);
  154. }
  155. /** _zplaced_filename_ ( str* str# dst* max# -- dst* ) [alias] _store_filename_
  156. * copy stringbuffer into a field as a zero-terminated filename-string,
  157. * a shell-homedir like "~username" will be expanded, and the
  158. * platform-specific dir-delimiter is converted in on the fly ('/' vs. '\\')
  159. */
  160. _export char*
  161. p4_store_filename (const p4_char_t* str, int n, char* dst, int max)
  162. {
  163. /* RENAME: p4_zplace_filename */
  164. int s = 0;
  165. int d;
  166. char* p;
  167. char* src = (char*) str;
  168. if (!src || !n) { *dst = '\0'; return dst; }
  169. # if PFE_DIR_DELIMITER == '\\'
  170. # define PFE_ANTI_DELIMITER '/'
  171. # else
  172. # define PFE_ANTI_DELIMITER '\\'
  173. # endif
  174. # define PFE_HOMEDIR_CHAR '~'
  175. *dst = '\0';
  176. if (n && max > n && *src == PFE_HOMEDIR_CHAR)
  177. {
  178. s = d = 1;
  179. while (s < n && d < max && src[s] && src[s] != PFE_DIR_DELIMITER)
  180. { dst[d++] = src[s++]; }
  181. dst[d] = '\0';
  182. if (s == 1)
  183. {
  184. p = getenv("HOME");
  185. if (p && max > p4_strlen(p)) { p4_strcpy (dst, p); }
  186. /* else *dst = '\0'; */
  187. }else{
  188. # if PFE_HAVE_PWD_H
  189. struct passwd *passwd = getpwnam (dst+1);
  190. if (passwd && max > p4_strlen (passwd->pw_dir))
  191. p4_strcpy (dst, passwd->pw_dir);
  192. else
  193. # endif
  194. *dst = PFE_DIR_DELIMITER; /* /user/restofpath */
  195. }
  196. }
  197. d = p4_strlen (dst);
  198. while (d < max && s < n && src[s])
  199. {
  200. if (src[s] != PFE_ANTI_DELIMITER)
  201. dst[d++] = src[s];
  202. else
  203. dst[d++] = PFE_DIR_DELIMITER;
  204. s++;
  205. }
  206. dst[d] = '\0';
  207. return dst;
  208. }
  209. /** _pocket_fileame_ ( str* str# -- dst* )
  210. * a new pocket with the given filename as asciiz
  211. : _pocket_filename_ _pocket_ /pocket _zplaced_filename_
  212. */
  213. _export P4_GCC_MALLOC char*
  214. p4_pocket_filename (const p4_char_t* src, int n)
  215. {
  216. /* RENAME: p4_pocket_zplace_filename */
  217. return p4_store_filename (src, n, p4_pocket (), P4_POCKET_SIZE);
  218. }
  219. /* **********************************************************************
  220. * expanding file names with paths and extensions
  221. */
  222. /* <try-extensions> ( zstr* zext* -- ?ok )
  223. * Append all extensions from ext to nm (which is assumed to be like a POCKET)
  224. * Check if file exists, if so return true, else false.
  225. * The nm-string is expected to be writeable up to max. pocket_size.
  226. */
  227. static int
  228. try_extensions (char* nm, const char *ext)
  229. {
  230. if (_P4_access (nm, F_OK) == 0)
  231. return 1;
  232. ___ int vv = p4_strlen (nm);
  233. if (!ext || vv > P4_POCKET_SIZE-4)
  234. return 0;
  235. while (*ext)
  236. {
  237. int v = vv;
  238. while (*ext && *ext == PFE_PATH_DELIMITER)
  239. { ext++; }
  240. do { nm[v++] = *ext++; }
  241. while (*ext && *ext != PFE_PATH_DELIMITER && v < P4_POCKET_SIZE-1);
  242. nm[v] = '\0';
  243. if (_P4_access (nm, F_OK) == 0)
  244. return 1;
  245. }
  246. nm[vv] = '\0';
  247. return 0; ____;
  248. }
  249. #if 0
  250. /*
  251. * if the src-path starts with "~" then expand the homedir
  252. * and append the rest of the path after the pathdelimiter.
  253. * In any case, the src-string is copied to the dst-string,
  254. * and the dst-string ist returned for further usage.
  255. */
  256. static char*
  257. strcpy_homedir (char* dst, const char* src)
  258. {
  259. if (*src != PFE_HOMEDIR_CHAR) { p4_strcpy (dst, src); return dst; }
  260. ___ const char* s = src+1; char* d = dst+1;
  261. while (*s && *s != PFE_DIR_DELIMITER) { *d++ = *s++; }
  262. *d = '\0';
  263. if (s == src+1)
  264. {
  265. d = getenv("HOME");
  266. if (d) { p4_strcpy (dst, d); } else *dst = '\0';
  267. }else{
  268. # if PFE_HAVE_PWD_H
  269. struct passwd *passwd = getpwnam (dst+1);
  270. if (passwd)
  271. p4_strcpy (dst, passwd->pw_dir);
  272. else
  273. # endif
  274. *dst = PFE_DIR_DELIMITER; /* /user/restofpath */
  275. }
  276. p4_strcat (dst, s);
  277. return dst; ____;
  278. }
  279. #endif
  280. /* <pocket-expanded-filename> ( str* str# zpaths* zexts* -- dst* )
  281. * str*,str# file name input
  282. * paths search path for files (a delimited series of dirname prefixes )
  283. * ext default file extensions (a delimited series of ext suffixes )
  284. * -> result in a pocket with the expanded filename, basically operate
  285. * as foreach dirname prefix run => <store-filename> to expand shellparticles
  286. * and if then => <try-extensions> returns true then return that one. If no
  287. * file was found to exist that way then just <store-filename> and return.
  288. */
  289. _export char*
  290. p4_pocket_expanded_filename (const p4_char_t *nm, int ln,
  291. const char *paths, const char *exts)
  292. {
  293. if (*nm == PFE_DIR_DELIMITER || *nm == PFE_HOMEDIR_CHAR)
  294. {
  295. char* path = p4_pocket ();
  296. p4_store_filename (nm, ln, path, P4_POCKET_SIZE);
  297. try_extensions (path, exts);
  298. return path;
  299. }else{
  300. char* path = p4_pocket ();
  301. p4_store_filename (nm, ln, path, P4_POCKET_SIZE);
  302. if (try_extensions (path, exts))
  303. return path;
  304. ___ char* pock = p4_pocket ();
  305. while (*paths)
  306. {
  307. char *p = pock;
  308. while (*paths && *paths == PFE_PATH_DELIMITER)
  309. { paths++; }
  310. if (!*paths) break;
  311. do { *p++ = *paths++; }
  312. while (*paths && *paths != PFE_PATH_DELIMITER);
  313. if (p[-1] != PFE_DIR_DELIMITER) *p++ = PFE_DIR_DELIMITER;
  314. ___ int fill = ln + (p - pock);
  315. if (fill > P4_POCKET_SIZE) continue;
  316. p4_strncpy (p, (char*) nm, ln);
  317. p4_store_filename ((p4_char_t*) pock, fill, path, P4_POCKET_SIZE);
  318. ____;
  319. if (try_extensions (path, exts))
  320. return path;
  321. }
  322. ____;
  323. p4_store_filename (nm, ln, path, P4_POCKET_SIZE);
  324. return path;
  325. }
  326. }
  327. /* **********************************************************************
  328. * string comparision and pattern matching
  329. */
  330. /** _search_ ( str* str# key* key# -- 0 | key-in-str* )
  331. * search for substring p2/u2 in string p1/u1, returns null if not found
  332. * or a pointer into str*,str# that has lenght of key#
  333. */
  334. _export char *
  335. p4_search (const char *p1, int u1, const char *p2, int u2)
  336. {
  337. if (u2 == 0)
  338. return (char *) p1;
  339. if (u2 > u1)
  340. return NULL;
  341. u1 -= u2;
  342. for (;;)
  343. {
  344. char *p = (char *) memchr (p1, *p2, u1 + 1);
  345. if (p == NULL)
  346. return NULL;
  347. if (p4_memcmp (p, p2, u2) == 0)
  348. return (char *) p;
  349. u1 -= p - p1;
  350. if (u1 == 0)
  351. return NULL;
  352. p1 = p + 1;
  353. u1--;
  354. }
  355. }
  356. /* match with a processed pattern, i.e. one without `\' escapes */
  357. static int
  358. do_match (const short *pattern, const char *string, int ic)
  359. {
  360. int c;
  361. for (;;)
  362. {
  363. --ic;
  364. switch (c = *pattern++)
  365. {
  366. case '\0':
  367. return *string == '\0';
  368. case -'*':
  369. while (*string && !do_match (pattern, string, ic))
  370. { --ic; string++; }
  371. continue;
  372. case -'?':
  373. if (*string++)
  374. continue;
  375. return 0;
  376. default:
  377. if (ic < 0)
  378. {
  379. if (*string++ == c)
  380. continue;
  381. }else{
  382. if (*string == c || *string == toupper(c))
  383. { string++; continue; }
  384. }
  385. return 0;
  386. }
  387. }
  388. }
  389. /** _match_ ( zpattern* zstring* ignorecase? -- yes? )
  390. * Match string against pattern.
  391. * Pattern knows wildcards `*' and `?' and `\' to escape a wildcard.
  392. */
  393. _export int
  394. p4_match (const char *pattern, const char *string, int ic)
  395. {
  396. /* RENAME: p4_wild_match - move near p4_wild_words - possibly export */
  397. short buf[0x100], *p = buf;
  398. /* preprocess pattern, remove `\' */
  399. for (;;)
  400. {
  401. int c = *(unsigned char *) pattern;
  402. pattern++;
  403. switch (c)
  404. {
  405. default:
  406. *p++ = c;
  407. continue;
  408. case '\0':
  409. *p = 0;
  410. break;
  411. case '?':
  412. *p++ = -'?';
  413. continue;
  414. case '*':
  415. *p++ = -'*';
  416. continue;
  417. case '\\':
  418. if (*pattern)
  419. *p++ = *pattern++;
  420. else
  421. *p++ = c;
  422. continue;
  423. }
  424. break;
  425. }
  426. /* match with preprocessed pattern */
  427. if (ic) ic = 31;
  428. return do_match (buf, string, ic);
  429. }
  430. /* _________________________________________________________________________
  431. * unsigned and floored divide and number i/o conversion
  432. */
  433. /** _U/_
  434. * unsigned divide procedure, single prec
  435. */
  436. _export P4_GCC_CONST udiv_t
  437. p4_udiv (p4ucell num, p4ucell denom)
  438. {
  439. udiv_t res;
  440. res.quot = num / denom;
  441. res.rem = num % denom;
  442. return res;
  443. }
  444. /** _/_
  445. * floored divide procedure, single prec
  446. */
  447. _export P4_GCC_CONST fdiv_t
  448. p4_fdiv (p4cell num, p4cell denom)
  449. {
  450. fdiv_t res;
  451. res.quot = num / denom;
  452. res.rem = num % denom;
  453. if (res.rem && (num ^ denom) < 0)
  454. {
  455. res.quot--;
  456. res.rem += denom;
  457. }
  458. return res;
  459. }
  460. /** _ud/_
  461. * Divides *ud by denom, leaves result in *ud, returns remainder.
  462. * For number output conversion: dividing by BASE.
  463. */
  464. _export p4ucell
  465. p4_u_d_div (p4udcell *ud, p4ucell denom)
  466. {
  467. p4udcell nom = *ud;
  468. udiv_t h;
  469. h = p4_udiv (P4xD0 (nom), denom);
  470. P4xD0 (*ud) = h.quot;
  471. P4xD0 (nom) = h.rem;
  472. h = p4_udiv (nom.hi, denom);
  473. P4xD1 (*ud) = h.quot;
  474. P4xD1 (nom) = h.rem;
  475. h = p4_udiv (P4xCELL (P4xD1 (nom), P4xD2 (nom)), denom);
  476. P4xD2 (*ud) = h.quot;
  477. P4xD2 (nom) = h.rem;
  478. h = p4_udiv (nom.lo, denom);
  479. P4xD3 (*ud) = h.quot;
  480. return h.rem;
  481. }
  482. /** _ud*_
  483. * Computes *ud * w + c, where w is actually only half of a cell in size.
  484. * Leaves result in *ud.
  485. * For number input conversion: multiply by BASE and add digit.
  486. */
  487. _export void
  488. p4_u_d_mul (p4udcell *ud, p4ucell w, p4ucell c)
  489. {
  490. c += P4xD3 (*ud) * w, P4xD3 (*ud) = P4xW1 (c), c >>= (sizeof(p4cell)*4);
  491. c += P4xD2 (*ud) * w, P4xD2 (*ud) = P4xW1 (c), c >>= (sizeof(p4cell)*4);
  492. c += P4xD1 (*ud) * w, P4xD1 (*ud) = P4xW1 (c), c >>= (sizeof(p4cell)*4);
  493. P4xD0 (*ud) = P4xD0 (*ud) * w + c;
  494. }
  495. /** _dig>num_ ( c n* base -- ?ok )
  496. * Get value of digit c into *n, return flag: valid digit.
  497. */
  498. _export int
  499. p4_dig2num (p4_char_t c, p4ucell *n, p4ucell base)
  500. {
  501. if (c < '0')
  502. return P4_FALSE;
  503. if (c <= '9')
  504. c -= '0';
  505. else
  506. {
  507. if (UPPER_CASE)
  508. c = toupper (c);
  509. if (c < 'A')
  510. return P4_FALSE;
  511. if (c <= 'Z')
  512. c -= 'A' - ('9' - '0' + 1);
  513. else
  514. {
  515. if (UPPER_CASE || c < 'a')
  516. return P4_FALSE;
  517. c -= 'a' - ('9' - '0' + 1) - ('Z' - 'A' + 1);
  518. }
  519. }
  520. if (c >= base)
  521. return P4_FALSE;
  522. *n = c;
  523. return P4_TRUE;
  524. }
  525. /** _num2dig_ ( val -- c )
  526. * make digit
  527. */
  528. _export P4_GCC_CONST char
  529. p4_num2dig (p4ucell n)
  530. {
  531. if (n < 10)
  532. return n + '0';
  533. if (n < 10 + 'Z' - 'A' + 1)
  534. return n - 10 + 'A';
  535. else
  536. return n - (10 + 'Z' - 'A' + 1) + 'a';
  537. }
  538. /** _hold_ ( c -- )
  539. * insert into pictured numeric output string
  540. */
  541. _export void
  542. p4_hold (char c)
  543. {
  544. if (p4_HLD <= DP)
  545. p4_throw (P4_ON_PICNUM_OVER);
  546. *--p4_HLD = c;
  547. }
  548. /** _>number_
  549. * try to convert into numer, see => >NUMBER
  550. */
  551. _export const p4_char_t *
  552. p4_to_number (const p4_char_t *p, p4ucell *n, p4udcell *d, p4ucell base)
  553. {
  554. #ifdef DEBUG /* good place to check some assertions (for debugging) */
  555. {
  556. auto p4udcell udbl;
  557. auto p4ucell_hi_lo hilo;
  558. p4_memset(&udbl, 0, sizeof(udbl));
  559. p4_memset(&hilo, 0, sizeof(hilo));
  560. if (sizeof(hilo) != sizeof(p4cell))
  561. { p4_outs(" {double-halfcell is not the size of cell} "); }
  562. if (sizeof(hilo.lo) != sizeof(p4cell)/2)
  563. { p4_outs(" {halfcell is not half the size of cell} "); }
  564. if (sizeof(hilo) != sizeof(udbl)/2)
  565. { p4_outs(" {double-halfcell is not half the size of double} "); }
  566. hilo.lo = 1;
  567. if ( (*(p4cell*)&hilo) != ((p4cell)1) )
  568. { p4_outs(" {double-halfcell is in incorrect (byteorder?)} "); }
  569. P4xD3(udbl) = 1;
  570. if ( udbl.lo != 1 )
  571. { p4_outs(" {double-lo-accessor is in incorrect (byteorder?)} "); }
  572. P4xD1(udbl) = 1;
  573. if ( udbl.hi != 1 )
  574. { p4_outs(" {double-hi-accessor is in incorrect (byteorder?)} "); }
  575. }
  576. #endif
  577. for (; *n > 0; p++, --*n)
  578. {
  579. p4ucell c;
  580. if (!p4_dig2num (*p, &c, base))
  581. break;
  582. p4_u_d_mul (d, base, c);
  583. if (p4_DPL >= 0)
  584. p4_DPL++;
  585. }
  586. return p;
  587. }
  588. /*
  589. * Options controlling input and output:
  590. */
  591. #ifndef USE_DOLLARHEX /* USER-CONFIG: */
  592. #define USE_DOLLARHEX 1 /* allow $XXX and %BBB input for hex and bin */
  593. #endif
  594. #ifndef PREFIX_HEX /* USER-CONFIG: */
  595. #define PREFIX_HEX '$' /* 0 or prefix for input of hex numbers */
  596. #endif
  597. #ifndef PREFIX_BINARY /* USER-CONFIG: */
  598. #define PREFIX_BINARY '%' /* 0 or prefix for input of binary numbers */
  599. #endif
  600. #ifndef PREFIX_DECIMAL /* USER-CONFIG: */
  601. #define PREFIX_DECIMAL '&' /* 0 or prefix for input of decimal numbers */
  602. #endif
  603. #ifndef PREFIX_0x /* USER-CONFIG: */
  604. #define PREFIX_0x 1 /* 0x10 =16, 0X100 = 256 */
  605. #endif
  606. #ifndef PREFIX_0o /* USER-CONFIG: */
  607. #define PREFIX_0o 1 /* 0o10 = 8, 0O100 = 64 */
  608. #endif
  609. #ifndef PREFIX_0b /* USER-CONFIG: */
  610. #define PREFIX_0b 1 /* 0b10 = 2, 0B100 = 4 */
  611. #endif
  612. /** _?number_ ( str* str# dcell* -- ?ok )
  613. * try to convert into number, see => ?NUMBER
  614. */
  615. _export int
  616. p4_number_question (const p4_char_t *p, p4ucell n, p4dcell *d)
  617. {
  618. p4ucell base = 0;
  619. int sign = 0;
  620. if (*p == '-') { p++; n--; sign = 1; }
  621. #if USE_DOLLARHEX
  622. if (p4_FLOAT_INPUT && n > 1)
  623. {
  624. switch (*p)
  625. {
  626. case PREFIX_HEX:
  627. base = 16; p++; n--;
  628. break;
  629. case PREFIX_BINARY:
  630. base = 2; p++; n--;
  631. break;
  632. case PREFIX_DECIMAL:
  633. base = 10; p++; n--;
  634. break;
  635. }
  636. }
  637. if (*p == '-') { if (sign) { return 0; } else { p++; n--; sign = 1; } }
  638. #endif
  639. #if PREFIX_0x || PREFIX_0o || PREFIX_0b
  640. if( ! base && n > 2 && *p == '0' )
  641. {
  642. switch(*(p+1))
  643. {
  644. # if (PREFIX_0x)
  645. case 'x':
  646. case 'X':
  647. if (BASE <= 10+'X'-'A') { base = 16; p+=2; n-=2; }
  648. break;
  649. # endif
  650. # if (PREFIX_0o)
  651. case 'o':
  652. case 'O':
  653. if (BASE <= 10+'O'-'A') { base = 8; p+=2; n-=2; }
  654. break;
  655. # endif
  656. # if (PREFIX_0b)
  657. case 'b':
  658. case 'B':
  659. if (BASE <= 10+'B'-'A') { base = 2; p+=2; n-=2; }
  660. break;
  661. # endif
  662. }
  663. }
  664. #endif
  665. if (base == 0)
  666. base = BASE;
  667. d->lo = d->hi = 0;
  668. p4_DPL = -1;
  669. p = p4_to_number (p, &n, (p4udcell *) d, base);
  670. if (n == 0)
  671. goto happy;
  672. if (*p != '.')
  673. return 0;
  674. p4_DPL = 0;
  675. p++;
  676. n--;
  677. p = p4_to_number (p, &n, (p4udcell *) d, base);
  678. if (n != 0)
  679. return 0;
  680. happy:
  681. if (sign)
  682. p4_d_negate (d);
  683. return 1;
  684. }
  685. /** _ud.r_ ( d,d str* str# base -- str* )
  686. * This is for internal use only (SEE and debugger),
  687. * The real => UD.R etc. words uses => HOLD and the memory area below => PAD
  688. */
  689. _export char *
  690. p4_str_ud_dot_r (p4udcell ud, char *p, int w, int base)
  691. {
  692. *--p = '\0';
  693. do {
  694. *--p = p4_num2dig (p4_u_d_div (&ud, base));
  695. w--;
  696. } while (ud.lo || ud.hi);
  697. while (w > 0) { *--p = ' '; w--; }
  698. return p;
  699. }
  700. /** _d.r_ ( d,d str* str# base -- str* )
  701. * This is for internal use only (SEE and debugger),
  702. * The real => UD.R etc. words use => HOLD and the memory area below => PAD
  703. */
  704. _export char *
  705. p4_str_d_dot_r (p4dcell d, char *p, int w, int base)
  706. {
  707. int sign = 0;
  708. if (d.hi < 0)
  709. p4_d_negate (&d), sign = 1;
  710. *--p = '\0';
  711. do {
  712. *--p = p4_num2dig (p4_u_d_div ((p4udcell *) &d, base));
  713. w--;
  714. } while (d.lo || d.hi);
  715. if (sign) { *--p = '-'; w--; }
  716. while (w > 0) { *--p = ' '; w--; }
  717. return p;
  718. }
  719. /** _._ ( i str* str# base -- str* )
  720. * This is for internal use only (SEE and debugger),
  721. * The real => . etc. words use => HOLD and the memory area below => PAD
  722. */
  723. _export char *
  724. p4_str_dot (p4cell n, char *p, int base)
  725. {
  726. p4dcell d;
  727. char *bl;
  728. *--p = '\0';
  729. bl = p - 1;
  730. d.lo = n;
  731. d.hi = n < 0 ? -1 : 0;
  732. p = p4_str_d_dot_r (d, p, 0, base);
  733. *bl = ' ';
  734. return p;
  735. }
  736. /* ********************************************************************** */
  737. /* console i/o */
  738. /* ********************************************************************** */
  739. /** _outc_ ( char -- ) [alias] _outc
  740. * emit single character,
  741. * (output adjusting the => OUT variable, see => _putc_ to do without)
  742. : _emit_ _putc_ _?xy_ drop out ! ;
  743. */
  744. _export void
  745. p4_outc (char c)
  746. {
  747. int x, y;
  748. p4_putc (c);
  749. p4_wherexy (&x, &y);
  750. p4_OUT = x;
  751. }
  752. /** _ztype_ ( zstr* -- ) [alias] _outs
  753. * type a string
  754. * (output adjusting the => OUT variable, see => _puts_ to do without)
  755. : _ztype_ _puts_ _?xy_ drop out ! ;
  756. */
  757. _export void
  758. p4_outs (const char *s) /* type a string */
  759. {
  760. int x = 0, y = 0;
  761. p4_puts (s);
  762. p4_wherexy (&x, &y);
  763. p4_OUT = x;
  764. }
  765. _export P4_GCC_PRINTF int
  766. p4_outf (const char *s,...);
  767. /** _outf_ ( ... zstr* -- n# )
  768. * type a string with formatting
  769. * (output adjusting the => OUT variable, see => _puts_ and => _outs_ )
  770. : _outf_ 0x200 lbuffer: buf[] buf[] _vsprintf_ buf[] _outs_ ;
  771. */
  772. int
  773. p4_outf (const char *s,...)
  774. {
  775. char buf[0x200];
  776. va_list p;
  777. int r;
  778. va_start (p, s);
  779. r = vsprintf (buf, s, p);
  780. p4_outs (buf);
  781. va_end (p);
  782. return r;
  783. }
  784. /** _type_ ( str* str# -- )
  785. * type counted string to terminal
  786. * (output adjusting the => OUT variable, see => _puts_ and => _outs_ )
  787. : _type_ 0 do c@++ _putc_ loop drop _flush_ _?xy drop out ! ;
  788. */
  789. _export void
  790. p4_type (const p4_char_t *str, p4cell len)
  791. {
  792. int x, y; const char* s = (const char*) str;
  793. while (--len >= 0)
  794. p4_putc_noflush (*s++);
  795. p4_wherexy (&x, &y);
  796. p4_OUT = x;
  797. p4_put_flush ();
  798. }
  799. /** _typeline_ ( str* str# -- )
  800. * type counted string to terminal, if it does not fit in full on
  801. * the current line, emit a => CR before
  802. * (output adjusting the OUT variable, see => _type_ and => _outs_ )
  803. : _typeline_ out @ over + cols @ > if cr then _type_ ;
  804. */
  805. _export void
  806. p4_type_on_line (const p4_char_t *str, p4cell len)
  807. {
  808. /* RENAME: ... might need p4_Q_cr variant... make macro from this? */
  809. if (p4_OUT + len >= p4_COLS)
  810. FX (p4_cr);
  811. p4_type (str, len);
  812. }
  813. /** _emits_ ( n# ch -- )
  814. * type a string of chars by repeating a single character which
  815. * is usually a space, see => SPACES
  816. * (output adjusting the OUT variable, see => _type_ and => _outs_ )
  817. : _emits_ swap 0 do dup _putc_ loop drop _flush_ _?xy_ drop out ! ;
  818. */
  819. _export void
  820. p4_emits (int n, const char c)
  821. {
  822. int x, y;
  823. while (--n >= 0)
  824. p4_putc_noflush (c);
  825. fflush (stdout);
  826. p4_wherexy (&x, &y);
  827. p4_OUT = x;
  828. }
  829. /** _tab_ ( n# -- )
  830. * type a string of space up to the next tabulator column
  831. * (output adjusting the OUT variable, see => _emits and => _typeonline )
  832. : _tab_ dup out @ - swap mod bl _emits_ ;
  833. */
  834. _export void
  835. p4_tab (int n)
  836. {
  837. p4_emits (n - p4_OUT % n, ' ');
  838. }
  839. /** _.line_ ( file* block# line# -- )
  840. */
  841. _export void
  842. p4_dot_line (p4_File *fid, p4cell n, p4cell l)
  843. {
  844. register p4_byte_t *p = p4_block (fid, n) + l * 64;
  845. p4_type (p, p4_dash_trailing (p, 64));
  846. }
  847. /** _get_line_ ( dst* dst# -- len# )
  848. * input a line with _fgets_ - will call => bye if no input, a trailing
  849. * newline will be dropped from the string and the length is returned
  850. */
  851. static int
  852. p4_get_line (char *p, p4cell n)
  853. {
  854. extern FCode (p4_bye);
  855. register char *q;
  856. /* if (! p) return 0; */
  857. q = fgets (p, n, stdin);
  858. if (q == NULL) FX (p4_bye);
  859. q = strrchr (p, '\n');
  860. if (q) *q = '\0';
  861. return p4_strlen (p);
  862. }
  863. /** _expect_noecho_ ( str* str# -- span# )
  864. * EXPECT counted string from terminal, without echo, so no real editing
  865. * it will however convert backspace and tabulators, break on newline/escape
  866. */
  867. static int
  868. p4_expect_noecho (char *p, p4cell n)
  869. {
  870. int i;
  871. char c;
  872. int out = 0;
  873. for (i = 0; i < n;)
  874. {
  875. switch (c = p4_getkey ())
  876. {
  877. default:
  878. p[i++] = c; out++;
  879. continue;
  880. case '\t':
  881. while (i < n)
  882. {
  883. p[i++] = ' '; out++;
  884. if (out % 8 == 0)
  885. break;
  886. }
  887. continue;
  888. case '\33':
  889. case '\r':
  890. case '\n':
  891. goto fin;
  892. case 127:
  893. case '\b':
  894. if (i <= 0)
  895. continue;
  896. i--; out--;
  897. continue;
  898. }
  899. }
  900. fin:
  901. p[i] = 0;
  902. SPAN = i;
  903. return i;
  904. }
  905. /** _expect_ ( str* str# -- span# )
  906. * EXPECT counted string from terminal, with echo, so one can use
  907. * simple editing facility with backspace, but nothing more.
  908. * it's very traditional, you want to use a lined-like function instead!
  909. */
  910. _export int
  911. p4_expect (char *p, p4cell n)
  912. {
  913. int i;
  914. char c;
  915. if (P4_opt.isnotatty == P4_TTY_NOECHO)
  916. return p4_expect_noecho (p, n);
  917. if (P4_opt.isnotatty)
  918. return p4_get_line (p, n);
  919. for (i = 0; i < n;)
  920. {
  921. switch (c = p4_getkey ())
  922. {
  923. default:
  924. p[i++] = c;
  925. p4_outc (c);
  926. continue;
  927. case 27:
  928. for (; i > 0; i--)
  929. FX (p4_backspace);
  930. continue;
  931. case '\t':
  932. while (i < n)
  933. {
  934. p[i++] = ' ';
  935. FX (p4_space);
  936. if (p4_OUT % 8 == 0)
  937. break;
  938. }
  939. continue;
  940. case '\r':
  941. case '\n':
  942. FX (p4_space);
  943. goto fin;
  944. case 127:
  945. case '\b':
  946. if (i <= 0)
  947. {
  948. p4_dot_bell ();
  949. continue;
  950. }
  951. i--;
  952. FX (p4_backspace);
  953. continue;
  954. }
  955. }
  956. fin:
  957. p[i] = 0;
  958. SPAN = i;
  959. return i;
  960. }
  961. /** _accept_ ( str* str# -- span# )
  962. * better input facility using lined if possible, otherwise
  963. * call _expect_noecho when running in a pipe or just _expect_ if no
  964. * real terminal attached.
  965. */
  966. _export int
  967. p4_accept (p4_char_t *tib, int n)
  968. {
  969. char* p = (char*) tib;
  970. if (P4_opt.isnotatty == P4_TTY_NOECHO)
  971. return p4_expect_noecho (p, n);
  972. if (P4_opt.isnotatty)
  973. return p4_get_line (p, n);
  974. PFE.accept_lined.string = p;
  975. PFE.accept_lined.max_length = n;
  976. p4_lined (&PFE.accept_lined, NULL);
  977. FX (p4_space);
  978. return PFE.accept_lined.length;
  979. }
  980. /* **********************************************************************
  981. * source input
  982. */
  983. /** QUERY ( -- )
  984. * source input: read from terminal using => _accept_ with the
  985. * returned string to show up in => TIB of => /TIB size.
  986. */
  987. FCode (p4_query)
  988. {
  989. SOURCE_ID = 0;
  990. BLK = 0;
  991. TO_IN = 0;
  992. TIB = PFE.tib;
  993. NUMBER_TIB = p4_accept (PFE.tib, TIB_SIZE);
  994. /* if (PFE.query_hook) // please use lined.h:lined->intercept now
  995. * NUMBER_TIB = (*PFE.query_hook)(NUMBER_TIB);
  996. */
  997. SPAN = NUMBER_TIB;
  998. }
  999. /**
  1000. * source input: read from text-file
  1001. */
  1002. _export int
  1003. p4_next_line (void)
  1004. {
  1005. p4cell ior;
  1006. p4ucell len;
  1007. len = sizeof SOURCE_FILE->buffer;
  1008. if (!p4_read_line (SOURCE_FILE->buffer, &len, SOURCE_FILE, &ior))
  1009. {
  1010. SOURCE_FILE->len = len;
  1011. return 0;
  1012. }
  1013. TIB = SOURCE_FILE->buffer;
  1014. NUMBER_TIB = SOURCE_FILE->len = len;
  1015. BLK = 0;
  1016. TO_IN = 0;
  1017. return 1;
  1018. }
  1019. /** _source_ ( str*& str#& -- )
  1020. * see => SOURCE - dispatch input source
  1021. */
  1022. _export void
  1023. p4_source (const p4_char_t **p, int *n)
  1024. {
  1025. switch (SOURCE_ID)
  1026. {
  1027. case -1: /* string from EVALUATE */
  1028. *p = TIB;
  1029. *n = NUMBER_TIB;
  1030. break;
  1031. case 0: /* string from QUERY or BLOCK */
  1032. if (BLK)
  1033. {
  1034. *p = p4_block (BLOCK_FILE, BLK);
  1035. *n = BPBUF;
  1036. }else{
  1037. *p = TIB;
  1038. *n = NUMBER_TIB;
  1039. }
  1040. break;
  1041. default: /* source line from text file */
  1042. *p = SOURCE_FILE->buffer;
  1043. *n = SOURCE_FILE->len;
  1044. }
  1045. }
  1046. /** _size_saved_input_ ( -- iframe-size )
  1047. */
  1048. _export p4ucell
  1049. p4_size_saved_input (void)
  1050. {
  1051. return sizeof (Iframe);
  1052. }
  1053. /*NOTE: the (void* p) is often the RP being aligned to 32bit on most
  1054. * platforms but an Iframe contains an .input.off possibly being 64bit
  1055. * wide when off_t=64bit. This creates an alignment problem. We fix it
  1056. * here with a CP operation. A better variant would be align the input
  1057. * pointer magically in p4_save_input, until someone calls p4_link_s..
  1058. */
  1059. /* I hate compiler bugs, especially this one for solaris gcc 2.95 : */
  1060. /* #define CP(X,I,Y) p4_memcpy ((char*)&(X), (char*)&(Y), (int)sizeof(X)) */
  1061. #define CP(X,I,Y) { register int i = sizeof((X)); \
  1062. p4_memcpy ((char*)&(X), (char*)&(Y), i); }
  1063. /** _link_saved_input_ ( iframe* -- )
  1064. * see => SAVE-INPUT
  1065. */
  1066. _export void
  1067. p4_link_saved_input (void *p)
  1068. {
  1069. Iframe *iframe = (Iframe *) p;
  1070. iframe->magic = P4_INPUT_MAGIC;
  1071. CP(iframe->input, =, PFE.input);
  1072. CP(iframe->prev, =, PFE.saved_input);
  1073. CP(PFE.saved_input, =, iframe);
  1074. }
  1075. /** _save_input_ ( iframe-stack* -- iframe-stack*' )
  1076. * see => SAVE-INPUT
  1077. */
  1078. _export void *
  1079. p4_save_input (void *p)
  1080. {
  1081. Iframe *iframe = (Iframe *) p;
  1082. --iframe;
  1083. p4_link_saved_input (iframe);
  1084. return ((void*) iframe);
  1085. }
  1086. /** _unlink_saved_input_ ( iframe* -- )
  1087. * see => RESTORE-INPUT
  1088. */
  1089. _export void
  1090. p4_unlink_saved_input (void *p)
  1091. {
  1092. Iframe *iframe = (Iframe *) p;
  1093. if (iframe->magic != P4_INPUT_MAGIC)
  1094. p4_throw (P4_ON_ARG_TYPE);
  1095. CP(PFE.input, = ,iframe->input);
  1096. CP(PFE.saved_input, =, iframe->prev);
  1097. }
  1098. /** _restore_input_ ( iframe-stack* -- iframe-stack*' )
  1099. * see => RESTORE-INPUT
  1100. */
  1101. _export void *
  1102. p4_restore_input (void *p)
  1103. {
  1104. Iframe *iframe = (Iframe *) p;
  1105. p4_unlink_saved_input (p);
  1106. ++iframe;
  1107. return ((void *) iframe);
  1108. }
  1109. /** _refill_ ( -- flag )
  1110. * see => REFILL
  1111. */
  1112. _export int
  1113. p4_refill (void)
  1114. {
  1115. switch (SOURCE_ID)
  1116. {
  1117. case -1:
  1118. return 0;
  1119. case 0:
  1120. if (BLK)
  1121. {
  1122. BLK++;
  1123. TO_IN = 0;
  1124. }else{
  1125. FX (p4_query);
  1126. }
  1127. return 1;
  1128. default:
  1129. return p4_next_line ();
  1130. }
  1131. }
  1132. /** _skip_delimiter_ ( del -- )
  1133. * => SKIP-DELIMITER
  1134. */
  1135. _export void
  1136. p4_skip_delimiter (char del)
  1137. {
  1138. const char *q;
  1139. int i, n;
  1140. p4_source ((const p4_char_t**) &q, &n);
  1141. if (del == ' ')
  1142. {
  1143. for (i = TO_IN;
  1144. i < n && p4_isascii (q[i]) && p4_isspace (q[i]);
  1145. i++)
  1146. {
  1147. ;
  1148. }
  1149. }else{
  1150. for (i = TO_IN; i < n && q[i] == del; i++)
  1151. {
  1152. ;
  1153. }
  1154. }
  1155. TO_IN = i;
  1156. }
  1157. /** _word:parse_ ( delim -- <end?> )
  1158. */
  1159. _export int
  1160. p4_word_parse (char del)
  1161. {
  1162. const char *q;
  1163. int i, n;
  1164. p4_source ((const p4_char_t**) &q, &n);
  1165. PFE.word.ptr = (p4_char_t*) q + TO_IN;
  1166. i = TO_IN;
  1167. if (i >= n)
  1168. goto empty;
  1169. if (del != ' ') /* no BL */
  1170. {
  1171. while (1)
  1172. {
  1173. if (q[i] == del)
  1174. goto delimfound;
  1175. i++;
  1176. if (i == n)
  1177. goto empty;
  1178. }
  1179. }else if (! p4_QUOTED_PARSE) /* BL and no QUOTED-PARSE */
  1180. {
  1181. while (1)
  1182. {
  1183. if (p4_isascii (q[i]) && p4_isspace (q[i]))
  1184. goto delimfound;
  1185. i++;
  1186. if (i == n)
  1187. goto empty;
  1188. }
  1189. #if 0
  1190. }else if (q[i] == '"') { /* scan "..." strings - including quotes */
  1191. i++;
  1192. while (1)
  1193. {
  1194. if (q[i++] == '"')
  1195. goto keepnextchar;
  1196. if (i == n)
  1197. goto empty;
  1198. }
  1199. #endif
  1200. }else{ /* BL && QUOTED -> before whitespace and after doublequote */
  1201. while (1)
  1202. {
  1203. if (p4_isascii (q[i]) && p4_isspace (q[i]))
  1204. goto delimfound;
  1205. if (q[i++] == '"')
  1206. goto keepnextchar;
  1207. if (i == n)
  1208. goto empty;
  1209. }
  1210. }
  1211. /* two exit sequences */
  1212. delimfound:
  1213. /* put the ">IN" pointer just after the delimiter that was found */
  1214. PFE.word.len = i - TO_IN;
  1215. TO_IN = i + 1;
  1216. return 1;
  1217. keepnextchar:
  1218. /* put the ">IN" pointer just after the delimiter that was found */
  1219. PFE.word.len = i - TO_IN;
  1220. TO_IN = i;
  1221. return 1;
  1222. empty:
  1223. /* no delimiter but end of parse area -> set ">IN" to n -> empty state */
  1224. PFE.word.len = i - TO_IN;
  1225. TO_IN = i; /* = n */
  1226. return 0;
  1227. }
  1228. /** _parse_ ( delim -- ptr len )
  1229. : _parse_ _word:parse_ _word*_ s! _word#_ s! ;
  1230. */
  1231. _export int
  1232. p4_parse (char del, const p4_char_t **p, p4ucell *l)
  1233. {
  1234. register int x = p4_word_parse(del);
  1235. *p = PFE.word.ptr;
  1236. *l = PFE.word.len;
  1237. return x;
  1238. }
  1239. /** _word>here_ ( -- here* )
  1240. * complement => _word:parse_ to arrive at the normal => WORD implementation
  1241. * will also ensure the string is zero-terminated - this makes a lot of
  1242. * operations easier since most forth function can receive a string-span
  1243. * directly but some need a string-copy and that is usually because it has
  1244. * to be passed down into a C-defined function with zerotermined string. Just
  1245. * use p4_HERE+1 (which is also the returnvalue of this function!) to have
  1246. * the start of the zero-terminated string. Note that this function may throw
  1247. * with P4_ON_PARSE_OVER if the string is too long (it has set *DP=0 to
  1248. * ensure again that => THROW will report PFE.word. as the offending string)
  1249. */
  1250. _export p4_char_t*
  1251. p4_word_to_here (void)
  1252. {
  1253. if (PFE.word.len > 255) /* (1<<CHAR_BITS)-1 */
  1254. { *DP = 0; p4_throw (P4_ON_PARSE_OVER); }
  1255. *DP = PFE.word.len;
  1256. p4_memcpy (DP+1, PFE.word.ptr, PFE.word.len);
  1257. (DP+1)[PFE.word.len] = 0; /* zero-terminated */
  1258. return (DP+1); /* p4_HERE+1 -> start of zero-terminated string */
  1259. }
  1260. /** _word_ ( del -- here* )
  1261. : _word_ dup _skip_delimiter_ _word:parse_ _word>here_ ;
  1262. */
  1263. _export p4_char_t *
  1264. p4_word (char del)
  1265. {
  1266. p4_skip_delimiter (del);
  1267. p4_word_parse (del);
  1268. p4_word_to_here ();
  1269. return p4_HERE;
  1270. }
  1271. /*
  1272. * PARSE-WORD a.k.a. BL PARSEWORD
  1273. *
  1274. * return and args mean the same as for => _parse_ but it really
  1275. * scans like => _word_. It most cases you can replace => _word_ with
  1276. * a sequence of _parseword_ and _word>here_ (.);
  1277. * The point is, that _parseword_ *doesn't* copy the next word onto
  1278. * here, it just returns the pointers. In some cases, esp. where
  1279. * a failure could be p4_thrown , it must be copied to HERE later.
  1280. * You can use _word2here_ for that. See _interpret_ for an example.
  1281. */
  1282. _export int
  1283. p4_word_parseword (char del)
  1284. {
  1285. /* quick path for wordset-loader: */
  1286. if (SOURCE_ID == -1 && PFE.word.len == -1) goto tib_static_string;
  1287. p4_skip_delimiter (del);
  1288. return p4_word_parse (del);
  1289. tib_static_string:
  1290. PFE.word.len = p4_strlen ((char*) PFE.word.ptr);
  1291. /* if (! FENCE) return; // libpfe.so is firing up */
  1292. /* assume: PFE.word.ptr points to the static_string we like to have */
  1293. TIB = PFE.word.ptr; NUMBER_TIB = PFE.word.len; TO_IN = 0;
  1294. return PFE.word.len;
  1295. }
  1296. #if 0
  1297. int
  1298. p4_parseword (char del, p4_char_t** p, p4ucell* l)
  1299. {
  1300. int x;
  1301. p4_skip_delimiter (del);
  1302. x = p4_word_parse (del);
  1303. *p = PFE.word.ptr;
  1304. *l = PFE.word.len;
  1305. return x;
  1306. }
  1307. #endif
  1308. /*@}*/
  1309. /* _________________________________________________________________________ */
  1310. /* _________________________________________________________________________ */
  1311. #if 0
  1312. /*
  1313. * here are a few implemenations to show you how we came to the above
  1314. * parsing code.
  1315. */
  1316. /**
  1317. * PARSE
  1318. */
  1319. int
  1320. # if 0 /* standard implementation */
  1321. p4_parse (char del, p4_char_t **p, p4ucell *l) /*1*/
  1322. {
  1323. char *q;
  1324. int i, n;
  1325. p4_source ((p4_char_t**) &q, &n);
  1326. *p = (p4_char_t*) q + TO_IN;
  1327. i = TO_IN;
  1328. if (del == ' ')
  1329. {
  1330. while (i < n && !(p4_isascii (q[i]) && p4_isspace (q[i])))
  1331. {
  1332. i++;
  1333. }
  1334. }else{
  1335. while (i < n && q[i] != del)
  1336. {
  1337. i++;
  1338. }
  1339. }
  1340. *l = i - TO_IN;
  1341. if (i == n)
  1342. {/* no delimiter but end of parse area -> set ">IN" to n -> empty state */
  1343. TO_IN = i;
  1344. return 0;
  1345. }else
  1346. {/* put the ">IN" pointer just after the delimiter that was found */
  1347. TO_IN = i + 1;
  1348. return 1;
  1349. }
  1350. }
  1351. # elif 0 /* split the while loop condition */
  1352. p4_parse (char del, p4_char_t **p, p4ucell *l) /*2*/
  1353. {
  1354. char *q;
  1355. int i, n;
  1356. p4_source ((p4_char_t**) &q, &n);
  1357. *p = (p4_char_t*) q + TO_IN;
  1358. i = TO_IN;
  1359. if (del == ' ')
  1360. {
  1361. while (1)
  1362. {
  1363. if (i >= n)
  1364. break;
  1365. if (p4_isascii (q[i]) && p4_isspace (q[i]))
  1366. break;
  1367. i++;
  1368. }
  1369. }else{
  1370. while (1)
  1371. {
  1372. if (i >= n)
  1373. break;
  1374. if (q[i] == del)
  1375. break;
  1376. i++;
  1377. }
  1378. }
  1379. *l = i - TO_IN;
  1380. if (i == n)
  1381. {/* no delimiter but end of parse area -> set ">IN" to n -> empty state */
  1382. TO_IN = i;
  1383. return 0;
  1384. }else
  1385. {/* put the ">IN" pointer just after the delimiter that was found */
  1386. TO_IN = i + 1;
  1387. return 1;
  1388. }
  1389. }
  1390. # elif 0 /* move the length setting inside the last if-check */
  1391. p4_parse (char del, char **p, p4ucell *l) /*3*/
  1392. {
  1393. char *q;
  1394. int i, n;
  1395. p4_source ((p4_char_t**) &q, &n);
  1396. *p = q + TO_IN;
  1397. i = TO_IN;
  1398. if (del == ' ')
  1399. {
  1400. while (1)
  1401. {
  1402. if (i >= n)
  1403. break;
  1404. if (p4_isascii (q[i]) && p4_isspace (q[i]))
  1405. break;
  1406. i++;
  1407. }
  1408. }else{
  1409. while (1)
  1410. {
  1411. if (i >= n)
  1412. break;
  1413. if (q[i] == del)
  1414. break;
  1415. i++;
  1416. }
  1417. }
  1418. if (i == n)
  1419. {/* no delimiter but end of parse area -> set ">IN" to n -> empty state */
  1420. *l = i - TO_IN;
  1421. TO_IN = i;
  1422. return 0;
  1423. }else
  1424. {/* put the ">IN" pointer just after the delimiter that was found */
  1425. *l = i - TO_IN;
  1426. TO_IN = i + 1;
  1427. return 1;
  1428. }
  1429. }
  1430. # elif 0 /* move an if(usedup)-check up front, and reverse order in whiles */
  1431. p4_parse (char del, char **p, p4ucell *l) /*4*/
  1432. {
  1433. char *q;
  1434. int i, n;
  1435. p4_source ((p4_char_t**) &q, &n);
  1436. *p = q + TO_IN;
  1437. i = TO_IN;
  1438. if (i >= n)
  1439. goto empty;
  1440. if (del == ' ')
  1441. {
  1442. while (1)
  1443. {
  1444. if (p4_isascii (q[i]) && p4_isspace (q[i]))
  1445. break;
  1446. i++;
  1447. if (i == n)
  1448. break;
  1449. }
  1450. }else{
  1451. while (1)
  1452. {
  1453. if (q[i] == del)
  1454. break;
  1455. i++;
  1456. if (i == n)
  1457. break;
  1458. }
  1459. }
  1460. empty:
  1461. if (i == n)
  1462. {/* no delimiter but end of parse area -> set ">IN" to n -> empty state */
  1463. *l = i - TO_IN;
  1464. TO_IN = i;
  1465. return 0;
  1466. }else
  1467. {/* put the ">IN" pointer just after the delimiter that was found */
  1468. *l = i - TO_IN;
  1469. TO_IN = i + 1;
  1470. return 1;
  1471. }
  1472. }
  1473. # elif 0 /* bind [if (i==n)] occurences */
  1474. p4_parse (char del, char **p, p4ucell *l) /*5*/
  1475. {
  1476. char *q;
  1477. int i, n;
  1478. p4_source ((p4_char_t**) &q, &n);
  1479. *p = q + TO_IN;
  1480. i = TO_IN;
  1481. if (i >= n)
  1482. goto empty;
  1483. if (del == ' ')
  1484. {
  1485. while (1)
  1486. {
  1487. if (p4_isascii (q[i]) && p4_isspace (q[i]))
  1488. break;
  1489. i++;
  1490. if (i == n)
  1491. goto empty;
  1492. }
  1493. }else{
  1494. while (1)
  1495. {
  1496. if (q[i] == del)
  1497. break;
  1498. i++;
  1499. if (i == n)
  1500. goto empty;
  1501. }
  1502. }
  1503. /* put the ">IN" pointer just after the delimiter that was found */
  1504. *l = i - TO_IN;
  1505. TO_IN = i + 1;
  1506. return 1;
  1507. empty:
  1508. /* no delimiter but end of parse area -> set ">IN" to n -> empty state */
  1509. *l = i - TO_IN;
  1510. TO_IN = i;
  1511. return 0;
  1512. }
  1513. # elif 0 /* make delimfound exit */
  1514. p4_parse (char del, char **p, p4ucell *l) /*6*/
  1515. {
  1516. char *q;
  1517. int i, n;
  1518. p4_source ((p4_char_t**) &q, &n);
  1519. *p = q + TO_IN;
  1520. i = TO_IN;
  1521. if (i >= n)
  1522. goto empty;
  1523. if (del == ' ')
  1524. {
  1525. while (1)
  1526. {
  1527. if (p4_isascii (q[i]) && p4_isspace (q[i]))
  1528. goto delimfound;
  1529. i++;
  1530. if (i == n)
  1531. goto empty;
  1532. }
  1533. }else{
  1534. while (1)
  1535. {
  1536. if (q[i] == del)
  1537. goto delimfound;
  1538. i++;
  1539. if (i == n)
  1540. goto empty;
  1541. }
  1542. }
  1543. /* two exit sequences */
  1544. delimfound:
  1545. /* put the ">IN" pointer just after the delimiter that was found */
  1546. *l = i - TO_IN;
  1547. TO_IN = i + 1;
  1548. return 1;
  1549. empty:
  1550. /* no delimiter but end of parse area -> set ">IN" to n -> empty state */
  1551. *l = i - TO_IN;
  1552. TO_IN = i;
  1553. return 0;
  1554. }
  1555. # elif 0 /* use global variables instead of p and l */
  1556. p4_parse (char del, char **p, p4ucell *l) /*7*/
  1557. {
  1558. register int x = _p4_parse(del);
  1559. *p = PFE.word.ptr;
  1560. *l = PFE.word.len;
  1561. return x;
  1562. }
  1563. int
  1564. p4_word_parse (char del)
  1565. {
  1566. char *q;
  1567. int i, n;
  1568. p4_source ((p4_char_t**) &q, &n);
  1569. PFE.word.ptr = q + TO_IN;
  1570. i = TO_IN;
  1571. if (i >= n)
  1572. goto empty;
  1573. if (del == ' ')
  1574. {
  1575. while (1)
  1576. {
  1577. if (p4_isascii (q[i]) && p4_isspace (q[i]))
  1578. goto delimfound;
  1579. i++;
  1580. if (i == n)
  1581. goto empty;
  1582. }
  1583. }else{
  1584. while (1)
  1585. {
  1586. if (q[i] == del)
  1587. goto delimfound;
  1588. i++;
  1589. if (i == n)
  1590. goto empty;
  1591. }
  1592. }
  1593. /* two exit sequences */
  1594. delimfound:
  1595. /* put the ">IN" pointer just after the delimiter that was found */
  1596. PFE.word.len = i - TO_IN;
  1597. TO_IN = i + 1;
  1598. return 1;
  1599. empty:
  1600. /* no delimiter but end of parse area -> set ">IN" to n -> empty state */
  1601. PFE.word.len = i - TO_IN;
  1602. TO_IN = i; /* = n */
  1603. return 0;
  1604. }
  1605. #else
  1606. /*
  1607. and finally, make p4_word depend also on p4_word_parse, and use the
  1608. global word.ptr/len to copy it to HERE afterwards. On the upside, we
  1609. can make the visual at p4_throw a bit better, since we can now show
  1610. the complete offending word-span, not just the point where ">in" had
  1611. stopped. And we avoid multiple code areas doing more or less the same
  1612. thing.
  1613. */
  1614. # endif
  1615. /*show parsecode */
  1616. #endif