home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2797 < prev    next >
Encoding:
Internet Message Format  |  1991-02-20  |  60.7 KB

  1. From: guido@cwi.nl (Guido van Rossum)
  2. Newsgroups: alt.sources
  3. Subject: Python 0.9.1 part 05/21
  4. Message-ID: <2967@charon.cwi.nl>
  5. Date: 19 Feb 91 17:41:32 GMT
  6.  
  7. : This is a shell archive.
  8. : Extract with 'sh this_file'.
  9. :
  10. : Extract part 01 first since it makes all directories
  11. echo 'Start of pack.out, part 05 out of 21:'
  12. if test -s 'demo/sgi/audio_stdwin/README'
  13. then echo '*** I will not over-write existing file demo/sgi/audio_stdwin/README'
  14. else
  15. echo 'x - demo/sgi/audio_stdwin/README'
  16. sed 's/^X//' > 'demo/sgi/audio_stdwin/README' << 'EOF'
  17. XThree programs that provide a user interface based upon STDWIN to the
  18. Xaudio device of the SGI 4D/25.  These scripts also demonstrate the power
  19. Xof a set of window interface classes implemented in Python that simplify
  20. Xthe construction of all sorts of buttons, etc.
  21. X
  22. Xjukebox        Browses a directory full of sound samples and lets you
  23. X        play selected ones.  (Probably not fully functional, it
  24. X        requires a conversion program.)
  25. X
  26. Xrec        A tape recorder that lets you record a sound sample,
  27. X        play it back, and save it to a file.  Various options to
  28. X        set sampling rate, volume etc.  When idle it doubles
  29. X        as a VU meter.
  30. X
  31. Xvumeter        A VU meter that displays a history of the volume of
  32. X        sound recently sampled from the microphone.
  33. EOF
  34. fi
  35. if test -s 'src/panelmodule.c'
  36. then echo '*** I will not over-write existing file src/panelmodule.c'
  37. else
  38. echo 'x - src/panelmodule.c'
  39. sed 's/^X//' > 'src/panelmodule.c' << 'EOF'
  40. X/***********************************************************
  41. XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
  42. XNetherlands.
  43. X
  44. X                        All Rights Reserved
  45. X
  46. XPermission to use, copy, modify, and distribute this software and its 
  47. Xdocumentation for any purpose and without fee is hereby granted, 
  48. Xprovided that the above copyright notice appear in all copies and that
  49. Xboth that copyright notice and this permission notice appear in 
  50. Xsupporting documentation, and that the names of Stichting Mathematisch
  51. XCentrum or CWI not be used in advertising or publicity pertaining to
  52. Xdistribution of the software without specific, written prior permission.
  53. X
  54. XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  55. XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  56. XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  57. XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  58. XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  59. XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  60. XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  61. X
  62. X******************************************************************/
  63. X
  64. X/* Panel module.
  65. X   Interface to the NASA Ames "panel library" for the SGI Graphics Library
  66. X   by David Tristram.
  67. X   
  68. X   NOTE: the panel library dumps core if you don't create a window before
  69. X   calling pnl.mkpanel().  A call to gl.winopen() suffices.
  70. X   If you don't want a window to be created, call gl.noport() before
  71. X   gl.winopen().
  72. X*/
  73. X
  74. X#include <gl.h>
  75. X#include <device.h>
  76. X#include <panel.h>
  77. X
  78. X#include "allobjects.h"
  79. X#include "import.h"
  80. X#include "modsupport.h"
  81. X#include "cgensupport.h"
  82. X
  83. X
  84. X/* The offsetof() macro calculates the offset of a structure member
  85. X   in its structure.  Unfortunately this cannot be written down portably,
  86. X   hence it is standardized by ANSI C.  For pre-ANSI C compilers,
  87. X   we give a version here that works usually (but watch out!): */
  88. X
  89. X#ifndef offsetof
  90. X#define offsetof(type, member) ( (int) & ((type*)0) -> member )
  91. X#endif
  92. X
  93. X
  94. X/* Panel objects */
  95. X
  96. Xtypedef struct {
  97. X    OB_HEAD
  98. X    Panel *ob_panel;
  99. X    object *ob_paneldict;
  100. X} panelobject;
  101. X
  102. Xextern typeobject Paneltype; /* Really static, forward */
  103. X
  104. X#define is_panelobject(v) ((v)->ob_type == &Paneltype)
  105. X
  106. X
  107. X/* Actuator objects */
  108. X
  109. Xtypedef struct {
  110. X    OB_HEAD
  111. X    Actuator *ob_actuator;
  112. X} actuatorobject;
  113. X
  114. Xextern typeobject Actuatortype; /* Really static, forward */
  115. X
  116. X#define is_actuatorobject(v) ((v)->ob_type == &Actuatortype)
  117. X
  118. Xstatic object *newactuatorobject(); /* Forward */
  119. X
  120. X
  121. X/* Since we allow different types of members than the functions from
  122. X   structmember.c, the memberlist stuff is replicated here.
  123. X   (Historically, it originated in this file and later became a generic
  124. X   feature.) */
  125. X
  126. X/* An array of memberlist structures defines the name, type and offset
  127. X   of selected members of a C structure.  These can be read by
  128. X   panel_getmember() and set by panel_setmember() (except if their
  129. X   READONLY flag is set).  The array must be terminated with an entry
  130. X   whose name pointer is NULL. */
  131. X
  132. Xstruct memberlist {
  133. X    char *name;
  134. X    int type;
  135. X    int offset;
  136. X    int readonly;
  137. X};
  138. X
  139. X/* Types */
  140. X#define T_SHORT        0
  141. X#define T_DEVICE    T_SHORT
  142. X#define T_LONG        1
  143. X#define T_INT        T_LONG
  144. X#define T_BOOL        T_LONG
  145. X#define T_FLOAT        2
  146. X#define T_COORD        T_FLOAT
  147. X#define T_STRING    3
  148. X#define T_FUNC        4
  149. X#define T_ACTUATOR    5
  150. X
  151. X/* Readonly flag */
  152. X#define READONLY    1
  153. X#define RO        READONLY        /* Shorthand */
  154. X
  155. Xstatic object *
  156. Xpanel_getmember(addr, mlist, name)
  157. X    char *addr;
  158. X    struct memberlist *mlist;
  159. X    char *name;
  160. X{
  161. X    object *v;
  162. X    register struct memberlist *l;
  163. X    
  164. X    for (l = mlist; l->name != NULL; l++) {
  165. X        if (strcmp(l->name, name) == 0) {
  166. X            addr += l->offset;
  167. X            switch (l->type) {
  168. X            case T_SHORT:
  169. X                v = newintobject((long) *(short*)addr);
  170. X                break;
  171. X            case T_LONG:
  172. X                v = newintobject(*(long*)addr);
  173. X                break;
  174. X            case T_FLOAT:
  175. X                v = newfloatobject(*(float*)addr);
  176. X                break;
  177. X            case T_STRING:
  178. X                if (*(char**)addr == NULL) {
  179. X                    INCREF(None);
  180. X                    v = None;
  181. X                }
  182. X                else
  183. X                    v = newstringobject(*(char**)addr);
  184. X                break;
  185. X            case T_ACTUATOR:
  186. X                v = newactuatorobject(*(Actuator**)addr);
  187. X                break;
  188. X            default:
  189. X                err_badarg();
  190. X                v = NULL;
  191. X            }
  192. X            return v;
  193. X        }
  194. X    }
  195. X    err_setstr(NameError, name);
  196. X    return NULL;
  197. X}
  198. X
  199. X/* Attempt to set a member.  Return: 0 if OK; 1 if not found; -1 if error */
  200. X
  201. Xstatic int
  202. Xpanel_setmember(addr, mlist, name, v)
  203. X    char *addr;
  204. X    struct memberlist *mlist;
  205. X    char *name;
  206. X    object *v;
  207. X{
  208. X    register struct memberlist *l;
  209. X    
  210. X    for (l = mlist; l->name != NULL; l++) {
  211. X        if (strcmp(l->name, name) == 0) {
  212. X            if (l->readonly) {
  213. X                err_setstr(TypeError, "read-only member");
  214. X                return -1;
  215. X            }
  216. X            addr += l->offset;
  217. X            switch (l->type) {
  218. X            case T_SHORT:
  219. X                if (!is_intobject(v)) {
  220. X                    err_setstr(TypeError, "int expected");
  221. X                    return -1;
  222. X                }
  223. X                *(short*)addr = getintvalue(v);
  224. X                break;
  225. X            case T_LONG:
  226. X                if (!is_intobject(v)) {
  227. X                    err_setstr(TypeError, "int expected");
  228. X                    return -1;
  229. X                }
  230. X                *(long*)addr = getintvalue(v);
  231. X                break;
  232. X            case T_FLOAT:
  233. X                if (is_intobject(v))
  234. X                    *(float*)addr = getintvalue(v);
  235. X                else if (is_floatobject(v))
  236. X                    *(float*)addr = getfloatvalue(v);
  237. X                else {
  238. X                    err_setstr(TypeError,"float expected");
  239. X                    return -1;
  240. X                }
  241. X                break;
  242. X            case T_STRING:
  243. X                /* XXX Should free(*(char**)addr) here
  244. X                   but it's dangerous since we don't know
  245. X                   if we set the label ourselves */
  246. X                if (v == None)
  247. X                    *(char**)addr = NULL;
  248. X                else if (!is_stringobject(v)) {
  249. X                    err_setstr(TypeError,
  250. X                            "string expected");
  251. X                    return -1;
  252. X                }
  253. X                else
  254. X                    *(char**)addr =
  255. X                        strdup(getstringvalue(v));
  256. X                break;
  257. X            case T_ACTUATOR:
  258. X                if (v == None)
  259. X                    *(Actuator**)addr = NULL;
  260. X                else if (!is_actuatorobject(v)) {
  261. X                    err_setstr(TypeError,
  262. X                            "actuator expected");
  263. X                    return -1;
  264. X                }
  265. X                else
  266. X                    *(Actuator**)addr =
  267. X                        ((actuatorobject *)v)->ob_actuator;
  268. X                break;
  269. X            default:
  270. X                err_setstr(SystemError, "unknown member type");
  271. X                return -1;
  272. X            }
  273. X            return 0; /* Found it */
  274. X        }
  275. X    }
  276. X    
  277. X    return 1; /* Not found */
  278. X}
  279. X
  280. X
  281. X/* Panel object methods */
  282. X
  283. Xstatic object *
  284. Xpanel_addpanel(self, args)
  285. X    panelobject *self;
  286. X    object *args;
  287. X{
  288. X    if (!getnoarg(args))
  289. X        return NULL;
  290. X    pnl_addpanel(self->ob_panel);
  291. X    INCREF(None);
  292. X    return None;
  293. X}
  294. X
  295. Xstatic object *
  296. Xpanel_endgroup(self, args)
  297. X    panelobject *self;
  298. X    object *args;
  299. X{
  300. X    if (!getnoarg(args))
  301. X        return NULL;
  302. X    pnl_endgroup(self->ob_panel);
  303. X    INCREF(None);
  304. X    return None;
  305. X}
  306. X
  307. Xstatic object *
  308. Xpanel_fixpanel(self, args)
  309. X    panelobject *self;
  310. X    object *args;
  311. X{
  312. X    if (!getnoarg(args))
  313. X        return NULL;
  314. X    pnl_fixpanel(self->ob_panel);
  315. X    INCREF(None);
  316. X    return None;
  317. X}
  318. X
  319. Xstatic object *
  320. Xpanel_strwidth(self, args)
  321. X    panelobject *self;
  322. X    object *args;
  323. X{
  324. X    object *v;
  325. X    double width;
  326. X    if (!getstrarg(args, &v))
  327. X        return NULL;
  328. X    width = pnl_strwidth(self->ob_panel, getstringvalue(v));
  329. X    return newfloatobject(width);
  330. X}
  331. X
  332. Xstatic struct methodlist panel_methods[] = {
  333. X    {"addpanel",        panel_addpanel},
  334. X    {"endgroup",        panel_endgroup},
  335. X    {"fixpanel",        panel_fixpanel},
  336. X    {"strwidth",        panel_strwidth},
  337. X    {NULL,            NULL}        /* sentinel */
  338. X};
  339. X
  340. Xstatic object *
  341. Xnewpanelobject()
  342. X{
  343. X    panelobject *p;
  344. X    p = NEWOBJ(panelobject, &Paneltype);
  345. X    if (p == NULL)
  346. X        return NULL;
  347. X    p->ob_panel = pnl_mkpanel();
  348. X    if ((p->ob_paneldict = newdictobject()) == NULL) {
  349. X        DECREF(p);
  350. X        return NULL;
  351. X    }
  352. X    return (object *)p;
  353. X}
  354. X
  355. Xstatic void
  356. Xpanel_dealloc(p)
  357. X    panelobject *p;
  358. X{
  359. X    pnl_delpanel(p->ob_panel);
  360. X    if (p->ob_paneldict != NULL)
  361. X        DECREF(p->ob_paneldict);
  362. X    DEL(p);
  363. X}
  364. X
  365. X
  366. X/* Table of panel members */
  367. X
  368. X#define PANOFF(member) offsetof(Panel, member)
  369. X
  370. Xstatic struct memberlist panel_memberlist[] = {
  371. X    {"id",        T_SHORT,    PANOFF(id),        READONLY},
  372. X    {"a",        T_ACTUATOR,    PANOFF(a),        READONLY},
  373. X    {"al",        T_ACTUATOR,    PANOFF(al),        READONLY},
  374. X    {"lastgroup",    T_ACTUATOR,    PANOFF(lastgroup),    READONLY},
  375. X    
  376. X    {"active",    T_BOOL,        PANOFF(active)},
  377. X    {"selectable",    T_BOOL,        PANOFF(selectable)},
  378. X
  379. X    {"x",        T_LONG,        PANOFF(x)},
  380. X    {"y",        T_LONG,        PANOFF(y)},
  381. X    {"w",        T_LONG,        PANOFF(w)},
  382. X    {"h",        T_LONG,        PANOFF(h)},
  383. X    
  384. X    {"minx",    T_COORD,    PANOFF(minx)},
  385. X    {"maxx",    T_COORD,    PANOFF(maxx)},
  386. X    {"miny",    T_COORD,    PANOFF(miny)},
  387. X    {"maxy",    T_COORD,    PANOFF(maxy)},
  388. X    
  389. X    {"cw",        T_COORD,    PANOFF(cw)},
  390. X    {"ch",        T_COORD,    PANOFF(ch)},
  391. X    
  392. X    {"gid",        T_LONG,        PANOFF(gid),        READONLY},
  393. X    {"usergid",    T_LONG,        PANOFF(usergid),    READONLY},
  394. X    
  395. X    {"vobj",    T_LONG,        PANOFF(vobj),        READONLY},
  396. X    {"ppu",        T_FLOAT,    PANOFF(ppu)},
  397. X    
  398. X    {"label",    T_STRING,    PANOFF(label)},
  399. X    
  400. X    /* Panel callbacks are not supported */
  401. X    
  402. X    {"visible",    T_BOOL,        PANOFF(visible)},
  403. X    {"somedirty",    T_INT,        PANOFF(somedirty)},
  404. X    {"dirtycnt",    T_INT,        PANOFF(dirtycnt)},
  405. X    
  406. X    /* T_PANEL is not supported */
  407. X    /*
  408. X    {"next",    T_PANEL,    PANOFF(next),        READONLY},
  409. X    */
  410. X    
  411. X    {NULL,        0,        0}        /* Sentinel */
  412. X};
  413. X
  414. Xstatic object *
  415. Xpanel_getattr(p, name)
  416. X    panelobject *p;
  417. X    char *name;
  418. X{
  419. X    object *v;
  420. X    
  421. X    v = dictlookup(p->ob_paneldict, name);
  422. X    if (v != NULL) {
  423. X        INCREF(v);
  424. X        return v;
  425. X    }
  426. X    
  427. X    v = findmethod(panel_methods, (object *)p, name);
  428. X    if (v != NULL)
  429. X        return v;
  430. X    err_clear();
  431. X    return panel_getmember((char *)p->ob_panel, panel_memberlist, name);
  432. X}
  433. X
  434. Xstatic int
  435. Xpanel_setattr(p, name, v)
  436. X    panelobject *p;
  437. X    char *name;
  438. X    object *v;
  439. X{
  440. X    int err;
  441. X    
  442. X    /* We don't allow deletion of attributes */
  443. X    if (v == NULL) {
  444. X        err_setstr(TypeError, "read-only panel attribute");
  445. X        return -1;
  446. X    }
  447. X    err = panel_setmember((char *)p->ob_panel, panel_memberlist, name, v);
  448. X    if (err != 1)
  449. X        return err;
  450. X    return dictinsert(p->ob_paneldict, name, v);
  451. X}
  452. X
  453. Xstatic typeobject Paneltype = {
  454. X    OB_HEAD_INIT(&Typetype)
  455. X    0,            /*ob_size*/
  456. X    "panel",        /*tp_name*/
  457. X    sizeof(panelobject),    /*tp_size*/
  458. X    0,            /*tp_itemsize*/
  459. X    /* methods */
  460. X    panel_dealloc,        /*tp_dealloc*/
  461. X    0,            /*tp_print*/
  462. X    panel_getattr,        /*tp_getattr*/
  463. X    panel_setattr,        /*tp_setattr*/
  464. X    0,            /*tp_compare*/
  465. X    0,            /*tp_repr*/
  466. X};
  467. X
  468. X
  469. X/* Descriptions of actuator-specific data members */
  470. X
  471. Xstruct memberlist slider_spec[] = {
  472. X    {"mode",    T_INT,        offsetof(Slider, mode)},
  473. X    {"finefactor",    T_FLOAT,    offsetof(Slider, finefactor)},
  474. X    {"differentialfactor",
  475. X            T_FLOAT,    offsetof(Slider, differentialfactor)},
  476. X    {"valsave",    T_FLOAT,    offsetof(Slider, valsave),    RO},
  477. X    {"wsave",    T_COORD,    offsetof(Slider, wsave)},
  478. X    {"bh",        T_COORD,    offsetof(Slider, bh)},
  479. X    {NULL}
  480. X};
  481. X
  482. X#define palette_spec slider_spec
  483. X
  484. Xstruct memberlist puck_spec[] = {
  485. X    /* Actuators already have members x and y, so the Puck's x and y
  486. X       have different names */
  487. X    {"puck_x",    T_FLOAT,    offsetof(Puck, x)},
  488. X    {"puck_y",    T_FLOAT,    offsetof(Puck, y)},
  489. X    {NULL}
  490. X};
  491. X
  492. Xstruct memberlist dial_spec[] = {
  493. X    {"mode",    T_INT,        offsetof(Dial, mode)},
  494. X    {"finefactor",    T_FLOAT,    offsetof(Dial, finefactor)},
  495. X    {"valsave",    T_FLOAT,    offsetof(Dial, valsave),    RO},
  496. X    {"wsave",    T_COORD,    offsetof(Dial, wsave)},
  497. X    {"winds",    T_FLOAT,    offsetof(Dial, winds)},
  498. X    {NULL}
  499. X};
  500. X
  501. Xstruct memberlist slideroid_spec[] = {
  502. X    {"mode",    T_INT,        offsetof(Slideroid, mode)},
  503. X    {"finemode",    T_BOOL,        offsetof(Slideroid, finemode)},
  504. X    {"resetmode",    T_BOOL,        offsetof(Slideroid, resetmode)},
  505. X    /* XXX Can't do resettarget (pointer to float) */
  506. X    /* XXX This makes resetval pretty useless... */
  507. X    /*
  508. X    {"resetval",    T_FLOAT,    offsetof(Slideroid, resetval)},
  509. X    */
  510. X    {"valsave",    T_FLOAT,    offsetof(Slideroid, valsave),    RO},
  511. X    {"wsave",    T_COORD,    offsetof(Slideroid, wsave)},
  512. X    {NULL}
  513. X};
  514. X
  515. Xstruct memberlist stripchart_spec[] = {
  516. X    {"firstpt",    T_INT,        offsetof(Stripchart, firstpt),    RO},
  517. X    {"lastpt",    T_INT,        offsetof(Stripchart, lastpt),    RO},
  518. X    {"Bind_Low",    T_BOOL,        offsetof(Stripchart, Bind_Low)},
  519. X    {"Bind_High",    T_BOOL,        offsetof(Stripchart, Bind_High)},
  520. X    /* XXX Can't do y (array of floats) */
  521. X    {"lowlabel",    T_ACTUATOR,    offsetof(Stripchart, lowlabel), RO},
  522. X    {"highlabel",    T_ACTUATOR,    offsetof(Stripchart, highlabel), RO},
  523. X    {NULL}
  524. X};
  525. X
  526. Xstruct memberlist typein_spec[] = {
  527. X    /* Note: these should be readonly after the actuator is added
  528. X       to a panel */
  529. X    {"str",        T_STRING,    offsetof(Typein, str)},
  530. X    {"len",        T_INT,        offsetof(Typein, len)},
  531. X    {NULL}
  532. X};
  533. X
  534. Xstruct memberlist typeout_spec[] = {
  535. X    {"mode",    T_INT,        offsetof(Typeout, mode)},
  536. X    /* XXX The buffer is managed by the actuator; but how do we
  537. X       add text? */
  538. X    {"buf",        T_STRING,    offsetof(Typeout, buf),    READONLY},
  539. X    {"delimstr",    T_STRING,    offsetof(Typeout, delimstr)},
  540. X    {"start",    T_INT,        offsetof(Typeout, start)},
  541. X    {"dot",        T_INT,        offsetof(Typeout, dot)},
  542. X    {"mark",    T_INT,        offsetof(Typeout, mark)},
  543. X    {"col",        T_INT,        offsetof(Typeout, col)},
  544. X    {"lin",        T_INT,        offsetof(Typeout, lin)},
  545. X    {"len",        T_INT,        offsetof(Typeout, len)},
  546. X    {"size",    T_INT,        offsetof(Typeout, size)},
  547. X    {NULL}
  548. X};
  549. X
  550. Xstruct memberlist mouse_spec[] = {
  551. X    /* Actuators already have members x and y, so the Mouse's x and y
  552. X       have different names */
  553. X    {"mouse_x",    T_FLOAT,    offsetof(Mouse, x)},
  554. X    {"mouse_y",    T_FLOAT,    offsetof(Mouse, y)},
  555. X    {NULL}
  556. X};
  557. X
  558. X#define MULOFF(member)    offsetof(Multislider, member)
  559. X
  560. Xstruct memberlist multislider_spec[] = {
  561. X    {"mode",    T_INT,        MULOFF(mode)},
  562. X    {"n",        T_INT,        MULOFF(n)},
  563. X    {"finefactor",    T_FLOAT,    MULOFF(finefactor)},
  564. X    {"wsave",    T_COORD,    MULOFF(wsave)},
  565. X    {"sa",        T_ACTUATOR,    MULOFF(sa)},
  566. X    {"bh",        T_COORD,    MULOFF(bh)},
  567. X    {"clrx",    T_COORD,    MULOFF(clrx)},
  568. X    {"clry",    T_COORD,    MULOFF(clry)},
  569. X    {"clrw",    T_COORD,    MULOFF(clrw)},
  570. X    {"clrh",    T_COORD,    MULOFF(clrh)},
  571. X    /* XXX acttype? */
  572. X    {NULL}
  573. X};
  574. X
  575. X/* XXX Still to do:
  576. X    Frame
  577. X    Icon
  578. X    Cycle
  579. X    Scroll
  580. X    Menu
  581. X*/
  582. X
  583. X/* List of known actuator initializer functions */
  584. X
  585. Xstruct {
  586. X    char *name;
  587. X    void (*func)();
  588. X    struct memberlist *spec;
  589. X} initializerlist[] = {
  590. X    {"analog_bar",            pnl_analog_bar},
  591. X    {"analog_meter",        pnl_analog_meter},
  592. X    {"button",            pnl_button},
  593. X    {"cycle",            pnl_cycle},
  594. X    /* Doesn't exist: */
  595. X/*    {"dhslider",            pnl_dhslider, slider_spec},    */
  596. X    {"dial",            pnl_dial, dial_spec},
  597. X    {"down_arrow_button",        pnl_down_arrow_button},
  598. X    {"down_double_arrow_button",    pnl_down_double_arrow_button},
  599. X    {"dvslider",            pnl_dvslider, slider_spec},
  600. X    {"filled_hslider",        pnl_filled_hslider, slider_spec},
  601. X    {"filled_slider",        pnl_filled_slider, slider_spec},
  602. X    {"filled_vslider",        pnl_filled_vslider, slider_spec},
  603. X    {"floating_puck",        pnl_floating_puck, puck_spec},
  604. X    {"frame",            pnl_frame},
  605. X    {"graphframe",            pnl_graphframe},
  606. X    {"hmultislider",        pnl_hmultislider, multislider_spec},
  607. X    {"hmultislider_bar",        pnl_hmultislider_bar},
  608. X    {"hmultislider_open_bar",    pnl_hmultislider_open_bar},
  609. X    {"hpalette",            pnl_hpalette, palette_spec},
  610. X    {"hslider",            pnl_hslider, slider_spec},
  611. X    {"icon",            pnl_icon},
  612. X    {"icon_menu",            pnl_icon_menu},
  613. X    {"label",            pnl_label},
  614. X    {"left_arrow_button",        pnl_left_arrow_button},
  615. X    {"left_double_arrow_button",    pnl_left_double_arrow_button},
  616. X    {"menu",            pnl_menu},
  617. X    {"menu_item",            pnl_menu_item},
  618. X    {"meter",            pnl_meter},
  619. X    {"mouse",            pnl_mouse, mouse_spec},
  620. X    {"multislider",            pnl_multislider, multislider_spec},
  621. X    {"multislider_bar",        pnl_multislider_bar},
  622. X    {"multislider_open_bar",    pnl_multislider_open_bar},
  623. X    {"palette",            pnl_palette, palette_spec},
  624. X    {"puck",            pnl_puck, puck_spec},
  625. X    {"radio_button",        pnl_radio_button},
  626. X    {"radio_check_button",        pnl_radio_check_button},
  627. X    {"right_arrow_button",        pnl_right_arrow_button},
  628. X    {"right_double_arrow_button",    pnl_right_double_arrow_button},
  629. X    {"rubber_puck",            pnl_rubber_puck, puck_spec},
  630. X    {"scale_chart",            pnl_scale_chart, stripchart_spec},
  631. X    {"scroll",            pnl_scroll},
  632. X    {"signal",            pnl_signal},
  633. X    {"slider",            pnl_slider, slider_spec},
  634. X    {"slideroid",            pnl_slideroid, slideroid_spec},
  635. X    {"strip_chart",            pnl_strip_chart, stripchart_spec},
  636. X    {"sub_menu",            pnl_sub_menu},
  637. X    {"toggle_button",        pnl_toggle_button},
  638. X    {"typein",            pnl_typein, typein_spec},
  639. X    {"typeout",            pnl_typeout, typeout_spec},
  640. X    {"up_arrow_button",        pnl_up_arrow_button},
  641. X    {"up_double_arrow_button",    pnl_up_double_arrow_button},
  642. X    {"viewframe",            pnl_viewframe},
  643. X    {"vmultislider",        pnl_vmultislider, multislider_spec},
  644. X    {"vmultislider_bar",        pnl_vmultislider_bar},
  645. X    {"vmultislider_open_bar",    pnl_vmultislider_open_bar},
  646. X    {"vpalette",            pnl_vpalette, palette_spec},
  647. X    {"vslider",            pnl_vslider, slider_spec},
  648. X    {"wide_button",            pnl_wide_button},
  649. X    {NULL,                NULL}        /* Sentinel */
  650. X};
  651. X
  652. X
  653. X/* Pseudo downfunc etc. */
  654. X
  655. Xstatic Actuator *down_pend, *active_pend, *up_pend;
  656. X
  657. Xstatic void
  658. Xdownfunc(a)
  659. X    Actuator *a;
  660. X{
  661. X    if (down_pend == NULL)
  662. X        down_pend = a;
  663. X}
  664. X
  665. Xstatic void
  666. Xactivefunc(a)
  667. X    Actuator *a;
  668. X{
  669. X    if (active_pend == NULL)
  670. X        active_pend = a;
  671. X}
  672. X
  673. Xstatic void
  674. Xupfunc(a)
  675. X    Actuator *a;
  676. X{
  677. X    if (up_pend == NULL)
  678. X        up_pend = a;
  679. X}
  680. X
  681. X
  682. X/* Lay-out for the user data */
  683. X
  684. Xstruct userdata {
  685. X    object *dict;    /* Dictionary object for additional attributes */
  686. X    struct memberlist *spec;    /* Actuator-specific members */
  687. X};
  688. X
  689. X
  690. X/* Create a new actuator; the actuator type is given as a string */
  691. X
  692. Xstatic Actuator *
  693. Xmakeactuator(name)
  694. X    char *name;
  695. X{
  696. X    Actuator *act;
  697. X    void (*initializer)() = NULL;
  698. X    int i;
  699. X    struct userdata *u;
  700. X    for (i = 0; initializerlist[i].name != NULL; i++) {
  701. X        if (strcmp(initializerlist[i].name, name) == 0) {
  702. X            initializer = initializerlist[i].func;
  703. X            break;
  704. X        }
  705. X    }
  706. X    if (initializerlist[i].name == NULL) {
  707. X        err_badarg();
  708. X        return NULL;
  709. X    }
  710. X    u = NEW(struct userdata, 1);
  711. X    if (u == NULL) {
  712. X        err_nomem();
  713. X        return NULL;
  714. X    }
  715. X    u->dict = NULL;
  716. X    u->spec = initializerlist[i].spec;
  717. X    act = pnl_mkact(initializer);
  718. X    act->u = (char *)u;
  719. X    act->downfunc = downfunc;
  720. X    act->activefunc = activefunc;
  721. X    act->upfunc = upfunc;
  722. X    return act;
  723. X}
  724. X
  725. X
  726. X/* Actuator objects methods */
  727. X
  728. Xstatic object *
  729. Xactuator_addact(self, args)
  730. X    actuatorobject *self;
  731. X    object *args;
  732. X{
  733. X    Panel *p;
  734. X    if (!is_panelobject(args)) {
  735. X        err_badarg();
  736. X        return NULL;
  737. X    }
  738. X    p = ((panelobject *)args) -> ob_panel;
  739. X    pnl_addact(self->ob_actuator, p);
  740. X    INCREF(None);
  741. X    return None;
  742. X}
  743. X
  744. Xstatic object *
  745. Xactuator_addsubact(self, args)
  746. X    actuatorobject *self;
  747. X    object *args;
  748. X{
  749. X    Actuator *a;
  750. X    if (!is_actuatorobject(args)) {
  751. X        err_badarg();
  752. X        return NULL;
  753. X    }
  754. X    a = ((actuatorobject *)args) -> ob_actuator;
  755. X    pnl_addsubact(self->ob_actuator, a);
  756. X    INCREF(None);
  757. X    return None;
  758. X}
  759. X
  760. Xstatic object *
  761. Xactuator_delact(self, args)
  762. X    actuatorobject *self;
  763. X    object *args;
  764. X{
  765. X    Panel *p;
  766. X    if (!getnoarg(args))
  767. X        return NULL;
  768. X    pnl_delact(self->ob_actuator);
  769. X    INCREF(None);
  770. X    return None;
  771. X}
  772. X
  773. Xstatic object *
  774. Xactuator_fixact(self, args)
  775. X    actuatorobject *self;
  776. X    object *args;
  777. X{
  778. X    Panel *p;
  779. X    if (!getnoarg(args))
  780. X        return NULL;
  781. X    pnl_fixact(self->ob_actuator);
  782. X    INCREF(None);
  783. X    return None;
  784. X}
  785. X
  786. Xstatic object *
  787. Xactuator_tprint(self, args)
  788. X    actuatorobject *self;
  789. X    object *args;
  790. X{
  791. X    object *str;
  792. X    if (self->ob_actuator->type != PNL_TYPEOUT) {
  793. X        err_setstr(TypeError, "tprint for non-typeout panel");
  794. X        return NULL;
  795. X    }
  796. X    if (!getstrarg(args, &str))
  797. X        return NULL;
  798. X    tprint(self->ob_actuator, getstringvalue(str));
  799. X    /* XXX Can't turn tprint's errors into exceptions, sorry */
  800. X    INCREF(None);
  801. X    return None;
  802. X}
  803. X
  804. Xstatic struct methodlist actuator_methods[] = {
  805. X    {"addact",        actuator_addact},
  806. X    {"addsubact",        actuator_addsubact},
  807. X    {"delact",        actuator_delact},
  808. X    {"fixact",        actuator_fixact},
  809. X    {"tprint",        actuator_tprint},
  810. X    {NULL,            NULL}        /* sentinel */
  811. X};
  812. X
  813. Xstatic object *
  814. Xnewactuatorobject(act)
  815. X    Actuator *act;
  816. X{
  817. X    actuatorobject *a;
  818. X    if (act == NULL) {
  819. X        INCREF(None);
  820. X        return None;
  821. X    }
  822. X    a = NEWOBJ(actuatorobject, &Actuatortype);
  823. X    if (a == NULL)
  824. X        return NULL;
  825. X    a->ob_actuator = act;
  826. X    return (object *)a;
  827. X}
  828. X
  829. Xstatic void
  830. Xactuator_dealloc(a)
  831. X    actuatorobject *a;
  832. X{
  833. X    /* Do NOT delete the actuator; most actuator objects are created
  834. X       to hold a temporary reference to an actuator, like one gotten
  835. X       from pnl_dopanel(). */
  836. X    
  837. X    DEL(a);
  838. X}
  839. X
  840. X
  841. X/* Table of actuator members */
  842. X
  843. X#define ACTOFF(member) offsetof(Actuator, member)
  844. X
  845. Xstruct memberlist act_memberlist[] = {
  846. X    {"id",        T_SHORT,    ACTOFF(id),        READONLY},
  847. X    
  848. X    /* T_PANEL is not defined */
  849. X    /*
  850. X    {"p",        T_PANEL,    ACTOFF(p),        READONLY},
  851. X    */
  852. X    
  853. X    {"pa",        T_ACTUATOR,    ACTOFF(pa),        READONLY},
  854. X    {"ca",        T_ACTUATOR,    ACTOFF(ca),        READONLY},
  855. X    {"al",        T_ACTUATOR,    ACTOFF(al),        READONLY},
  856. X    {"na",        T_INT,        ACTOFF(na),        READONLY},
  857. X    {"type",    T_INT,        ACTOFF(type),        READONLY},
  858. X    {"active",    T_BOOL,        ACTOFF(active)},
  859. X    
  860. X    {"x",        T_COORD,    ACTOFF(x)},
  861. X    {"y",        T_COORD,    ACTOFF(y)},
  862. X    {"w",        T_COORD,    ACTOFF(w)},
  863. X    {"h",        T_COORD,    ACTOFF(h)},
  864. X
  865. X    {"lx",        T_COORD,    ACTOFF(lx)},
  866. X    {"ly",        T_COORD,    ACTOFF(ly)},
  867. X    {"lw",        T_COORD,    ACTOFF(lw)},
  868. X    {"lh",        T_COORD,    ACTOFF(lh)},
  869. X    {"ld",        T_COORD,    ACTOFF(ld)},
  870. X
  871. X    {"val",        T_FLOAT,    ACTOFF(val)},
  872. X    {"extval",    T_FLOAT,    ACTOFF(extval)},
  873. X    {"initval",    T_FLOAT,    ACTOFF(initval)},
  874. X    {"maxval",    T_FLOAT,    ACTOFF(maxval)},
  875. X    {"minval",    T_FLOAT,    ACTOFF(minval)},
  876. X    {"scalefactor",    T_FLOAT,    ACTOFF(scalefactor)},
  877. X    
  878. X    {"label",    T_STRING,    ACTOFF(label)},
  879. X    {"key",        T_DEVICE,    ACTOFF(key)},
  880. X    {"labeltype",    T_INT,        ACTOFF(labeltype)},
  881. X    
  882. X    /* Internal callbacks are not supported;
  883. X       user callbacks are treated special! */
  884. X    
  885. X    {"dirtycnt",    T_INT,        ACTOFF(dirtycnt)},
  886. X    
  887. X    /* members u and data are accessed differently */
  888. X    
  889. X    {"automatic",    T_BOOL,        ACTOFF(automatic)},
  890. X    {"selectable",    T_BOOL,        ACTOFF(selectable)},
  891. X    {"visible",    T_BOOL,        ACTOFF(visible)},
  892. X    {"beveled",    T_BOOL,        ACTOFF(beveled)},
  893. X    
  894. X    {"group",    T_ACTUATOR,    ACTOFF(group),        READONLY},
  895. X    {"next",    T_ACTUATOR,    ACTOFF(next),        READONLY},
  896. X    
  897. X    {NULL,        0,        0}        /* Sentinel */
  898. X};
  899. X
  900. X
  901. X/* Potential name conflicts between attributes are solved as follows.
  902. X   - Actuator-specific attributes always override generic attributes.
  903. X   - When reading, the dictionary has overrides everything else;
  904. X     when writing, everything else overrides the dictionary.
  905. X   - When reading, methods are tried last.
  906. X*/
  907. X
  908. Xstatic object *
  909. Xactuator_getattr(a, name)
  910. X    actuatorobject *a;
  911. X    char *name;
  912. X{
  913. X    Actuator *act = a->ob_actuator;
  914. X    struct userdata *u = (struct userdata *) act->u;
  915. X    object *v;
  916. X    
  917. X    if (u != NULL) {
  918. X        /* 1. Try the dictionary */
  919. X        if (u->dict != NULL) {
  920. X            v = dictlookup(u->dict, name);
  921. X            if (v != NULL) {
  922. X                INCREF(v);
  923. X                return v;
  924. X            }
  925. X        }
  926. X        
  927. X        /* 2. Try actuator-specific attributes */
  928. X        if (u->spec != NULL) {
  929. X            v = panel_getmember(act->data, u->spec, name);
  930. X            if (v != NULL)
  931. X                return v;
  932. X            err_clear();
  933. X        }
  934. X    }
  935. X    
  936. X    /* 3. Try generic actuator attributes */
  937. X    v = panel_getmember((char *)act, act_memberlist, name);
  938. X    if (v != NULL)
  939. X        return v;
  940. X    
  941. X    /* 4. Try methods */
  942. X    err_clear();
  943. X    return findmethod(actuator_methods, (object *)a, name);
  944. X}
  945. X
  946. Xstatic int
  947. Xactuator_setattr(a, name, v)
  948. X    actuatorobject *a;
  949. X    char *name;
  950. X    object *v;
  951. X{
  952. X    Actuator *act = a->ob_actuator;
  953. X    struct userdata *u = (struct userdata *) act->u;
  954. X    int err;
  955. X    
  956. X    /* 0. We don't allow deletion of attributes */
  957. X    if (v == NULL) {
  958. X        err_setstr(TypeError, "read-only actuator attribute");
  959. X        return -1;
  960. X    }
  961. X    
  962. X    /* 1. Try actuator-specific attributes */
  963. X    if (u != NULL && u->spec != NULL) {
  964. X        err = panel_setmember(act->data, u->spec, name, v);
  965. X        if (err != 1)
  966. X            return err;
  967. X    }
  968. X    
  969. X    /* 2. Try generic actuator attributes */
  970. X    err = panel_setmember((char *)act, act_memberlist, name, v);
  971. X    if (err != 1)
  972. X        return err;
  973. X    
  974. X    /* 3. Try the dictionary */
  975. X    if (u != NULL) {
  976. X        if (u->dict == NULL && (u->dict = newdictobject()) == NULL)
  977. X            return NULL;
  978. X        return dictinsert(u->dict, name, v);
  979. X    }
  980. X    
  981. X    err_setstr(NameError, name);
  982. X    return -1;
  983. X}
  984. X
  985. Xstatic int
  986. Xactuator_compare(v, w)
  987. X    actuatorobject *v, *w;
  988. X{
  989. X    long i = (long)v->ob_actuator;
  990. X    long j = (long)w->ob_actuator;
  991. X    return (i < j) ? -1 : (i > j) ? 1 : 0;
  992. X}
  993. X
  994. Xstatic typeobject Actuatortype = {
  995. X    OB_HEAD_INIT(&Typetype)
  996. X    0,            /*ob_size*/
  997. X    "actuator",        /*tp_name*/
  998. X    sizeof(actuatorobject),    /*tp_size*/
  999. X    0,            /*tp_itemsize*/
  1000. X    /* methods */
  1001. X    actuator_dealloc,    /*tp_dealloc*/
  1002. X    0,            /*tp_print*/
  1003. X    actuator_getattr,    /*tp_getattr*/
  1004. X    actuator_setattr,    /*tp_setattr*/
  1005. X    actuator_compare,    /*tp_compare*/
  1006. X    0,            /*tp_repr*/
  1007. X};
  1008. X
  1009. X
  1010. X/* The panel module itself */
  1011. X
  1012. Xstatic object *
  1013. Xmodule_mkpanel(self, args)
  1014. X    object *self;
  1015. X    object *args;
  1016. X{
  1017. X    if (!getnoarg(args))
  1018. X        return NULL;
  1019. X    return newpanelobject();
  1020. X}
  1021. X
  1022. Xstatic object *
  1023. Xmodule_mkact(self, args)
  1024. X    object *self;
  1025. X    object *args;
  1026. X{
  1027. X    object *v;
  1028. X    Actuator *a;
  1029. X    if (!getstrarg(args, &v))
  1030. X        return NULL;
  1031. X    a = makeactuator(getstringvalue(v));
  1032. X    if (a == NULL)
  1033. X        return NULL;
  1034. X    return newactuatorobject(a);
  1035. X}
  1036. X
  1037. Xstatic object *
  1038. Xmodule_dopanel(self, args)
  1039. X    object *self;
  1040. X    object *args;
  1041. X{
  1042. X    Actuator *a;
  1043. X    object *v, *w;
  1044. X    if (!getnoarg(args))
  1045. X        return NULL;
  1046. X    a = pnl_dopanel();
  1047. X    v = newtupleobject(4);
  1048. X    if (v == NULL)
  1049. X        return NULL;
  1050. X    settupleitem(v, 0, newactuatorobject(a));
  1051. X    settupleitem(v, 1, newactuatorobject(down_pend));
  1052. X    settupleitem(v, 2, newactuatorobject(active_pend));
  1053. X    settupleitem(v, 3, newactuatorobject(up_pend));
  1054. X    down_pend = active_pend = up_pend = NULL;
  1055. X    return v;
  1056. X}
  1057. X
  1058. Xstatic object *
  1059. Xmodule_drawpanel(self, args)
  1060. X    object *self;
  1061. X    object *args;
  1062. X{
  1063. X    if (!getnoarg(args))
  1064. X        return NULL;
  1065. X    pnl_drawpanel();
  1066. X    INCREF(None);
  1067. X    return None;
  1068. X}
  1069. X
  1070. Xstatic object *
  1071. Xmodule_needredraw(self, args)
  1072. X    object *self;
  1073. X    object *args;
  1074. X{
  1075. X    if (!getnoarg(args))
  1076. X        return NULL;
  1077. X    pnl_needredraw();
  1078. X    INCREF(None);
  1079. X    return None;
  1080. X}
  1081. X
  1082. Xstatic object *
  1083. Xmodule_userredraw(self, args)
  1084. X    object *self;
  1085. X    object *args;
  1086. X{
  1087. X    short wid;
  1088. X    if (!getnoarg(args))
  1089. X        return NULL;
  1090. X    wid = pnl_userredraw();
  1091. X    return newintobject((long)wid);
  1092. X}
  1093. X
  1094. Xstatic object *
  1095. Xmodule_block(self, args)
  1096. X    object *self;
  1097. X    object *args;
  1098. X{
  1099. X    int flag;
  1100. X    if (!getintarg(args, &flag))
  1101. X        return NULL;
  1102. X    pnl_block = flag;
  1103. X    INCREF(None);
  1104. X    return None;
  1105. X}
  1106. X
  1107. Xstatic struct methodlist module_methods[] = {
  1108. X    {"block",        module_block},
  1109. X    {"dopanel",        module_dopanel},
  1110. X    {"drawpanel",        module_drawpanel},
  1111. X    {"mkpanel",        module_mkpanel},
  1112. X    {"mkact",        module_mkact},
  1113. X    {"needredraw",        module_needredraw},
  1114. X    {"userredraw",        module_userredraw},
  1115. X    {NULL,            NULL}        /* sentinel */
  1116. X};
  1117. X
  1118. Xvoid
  1119. Xinitpanel()
  1120. X{
  1121. X    /* Setting pnl_block to 1 would greatly reduce the CPU usage
  1122. X       of an idle application.  Unfortunately it also breaks our
  1123. X       little hacks to get callback functions in Python called.
  1124. X       So we clear pnl_block here.  You can set/clear pnl_block
  1125. X       from Python using pnl.block(flag).  It works if you have
  1126. X       no upfuncs. */
  1127. X    pnl_block = 0;
  1128. X    initmodule("pnl", module_methods);
  1129. X}
  1130. EOF
  1131. fi
  1132. if test -s 'src/regexp.c'
  1133. then echo '*** I will not over-write existing file src/regexp.c'
  1134. else
  1135. echo 'x - src/regexp.c'
  1136. sed 's/^X//' > 'src/regexp.c' << 'EOF'
  1137. X/***********************************************************
  1138. XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
  1139. XNetherlands.
  1140. X
  1141. X                        All Rights Reserved
  1142. X
  1143. XPermission to use, copy, modify, and distribute this software and its 
  1144. Xdocumentation for any purpose and without fee is hereby granted, 
  1145. Xprovided that the above copyright notice appear in all copies and that
  1146. Xboth that copyright notice and this permission notice appear in 
  1147. Xsupporting documentation, and that the names of Stichting Mathematisch
  1148. XCentrum or CWI not be used in advertising or publicity pertaining to
  1149. Xdistribution of the software without specific, written prior permission.
  1150. X
  1151. XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  1152. XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  1153. XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  1154. XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  1155. XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  1156. XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  1157. XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  1158. X
  1159. X******************************************************************/
  1160. X
  1161. X/*
  1162. X * regcomp and regexec -- regsub and regerror are elsewhere
  1163. X *
  1164. X *    Copyright (c) 1986 by University of Toronto.
  1165. X *    Written by Henry Spencer.  Not derived from licensed software.
  1166. X#ifdef MULTILINE
  1167. X *    Changed by Guido van Rossum, CWI, Amsterdam
  1168. X *    for multi-line support.
  1169. X#endif
  1170. X *
  1171. X *    Permission is granted to anyone to use this software for any
  1172. X *    purpose on any computer system, and to redistribute it freely,
  1173. X *    subject to the following restrictions:
  1174. X *
  1175. X *    1. The author is not responsible for the consequences of use of
  1176. X *        this software, no matter how awful, even if they arise
  1177. X *        from defects in it.
  1178. X *
  1179. X *    2. The origin of this software must not be misrepresented, either
  1180. X *        by explicit claim or by omission.
  1181. X *
  1182. X *    3. Altered versions must be plainly marked as such, and must not
  1183. X *        be misrepresented as being the original software.
  1184. X *
  1185. X * Beware that some of this code is subtly aware of the way operator
  1186. X * precedence is structured in regular expressions.  Serious changes in
  1187. X * regular-expression syntax might require a total rethink.
  1188. X */
  1189. X#include <stdio.h>
  1190. X#include "PROTO.h"
  1191. X#include "malloc.h"
  1192. X#undef ANY /* Conflicting identifier defined in malloc.h */
  1193. X#include <string.h>        /* XXX Remove if not found */
  1194. X#include "regexp.h"
  1195. X#include "regmagic.h"
  1196. X
  1197. X#ifdef MULTILINE
  1198. X/*
  1199. X * Defining MULTILINE turns on the following changes in the semantics:
  1200. X * 1.    The '.' operator matches all characters except a newline.
  1201. X * 2.    The '^' operator matches at the beginning of the string or after
  1202. X *    a newline.  (Anchored matches are retried after each newline.)
  1203. X * 3.    The '$' operator matches at the end of the string or before
  1204. X *    a newline.
  1205. X * 4.    A '\' followed by an 'n' matches a newline.  (This is an
  1206. X *    unfortunate exception to the rule that '\' followed by a
  1207. X *    character matches that character...)
  1208. X *
  1209. X * Also, there is a new function reglexec(prog, string, offset)
  1210. X * which searches for a match starting at 'string+offset';
  1211. X * it differs from regexec(prog, string+offset) in assuming
  1212. X * that the line begins at 'string'.
  1213. X */
  1214. X#endif
  1215. X
  1216. X/*
  1217. X * The "internal use only" fields in regexp.h are present to pass info from
  1218. X * compile to execute that permits the execute phase to run lots faster on
  1219. X * simple cases.  They are:
  1220. X *
  1221. X * regstart    char that must begin a match; '\0' if none obvious
  1222. X * reganch    is the match anchored (at beginning-of-line only)?
  1223. X * regmust    string (pointer into program) that match must include, or NULL
  1224. X * regmlen    length of regmust string
  1225. X *
  1226. X * Regstart and reganch permit very fast decisions on suitable starting points
  1227. X * for a match, cutting down the work a lot.  Regmust permits fast rejection
  1228. X * of lines that cannot possibly match.  The regmust tests are costly enough
  1229. X * that regcomp() supplies a regmust only if the r.e. contains something
  1230. X * potentially expensive (at present, the only such thing detected is * or +
  1231. X * at the start of the r.e., which can involve a lot of backup).  Regmlen is
  1232. X * supplied because the test in regexec() needs it and regcomp() is computing
  1233. X * it anyway.
  1234. X */
  1235. X
  1236. X/*
  1237. X * Structure for regexp "program".  This is essentially a linear encoding
  1238. X * of a nondeterministic finite-state machine (aka syntax charts or
  1239. X * "railroad normal form" in parsing technology).  Each node is an opcode
  1240. X * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
  1241. X * all nodes except BRANCH implement concatenation; a "next" pointer with
  1242. X * a BRANCH on both ends of it is connecting two alternatives.  (Here we
  1243. X * have one of the subtle syntax dependencies:  an individual BRANCH (as
  1244. X * opposed to a collection of them) is never concatenated with anything
  1245. X * because of operator precedence.)  The operand of some types of node is
  1246. X * a literal string; for others, it is a node leading into a sub-FSM.  In
  1247. X * particular, the operand of a BRANCH node is the first node of the branch.
  1248. X * (NB this is *not* a tree structure:  the tail of the branch connects
  1249. X * to the thing following the set of BRANCHes.)  The opcodes are:
  1250. X */
  1251. X
  1252. X/* definition    number    opnd?    meaning */
  1253. X#define    END    0    /* no    End of program. */
  1254. X#define    BOL    1    /* no    Match "" at beginning of line. */
  1255. X#define    EOL    2    /* no    Match "" at end of line. */
  1256. X#define    ANY    3    /* no    Match any one character. */
  1257. X#define    ANYOF    4    /* str    Match any character in this string. */
  1258. X#define    ANYBUT    5    /* str    Match any character not in this string. */
  1259. X#define    BRANCH    6    /* node    Match this alternative, or the next... */
  1260. X#define    BACK    7    /* no    Match "", "next" ptr points backward. */
  1261. X#define    EXACTLY    8    /* str    Match this string. */
  1262. X#define    NOTHING    9    /* no    Match empty string. */
  1263. X#define    STAR    10    /* node    Match this (simple) thing 0 or more times. */
  1264. X#define    PLUS    11    /* node    Match this (simple) thing 1 or more times. */
  1265. X#define    OPEN    20    /* no    Mark this point in input as start of #n. */
  1266. X            /*    OPEN+1 is number 1, etc. */
  1267. X#define    CLOSE    30    /* no    Analogous to OPEN. */
  1268. X
  1269. X/*
  1270. X * Opcode notes:
  1271. X *
  1272. X * BRANCH    The set of branches constituting a single choice are hooked
  1273. X *        together with their "next" pointers, since precedence prevents
  1274. X *        anything being concatenated to any individual branch.  The
  1275. X *        "next" pointer of the last BRANCH in a choice points to the
  1276. X *        thing following the whole choice.  This is also where the
  1277. X *        final "next" pointer of each individual branch points; each
  1278. X *        branch starts with the operand node of a BRANCH node.
  1279. X *
  1280. X * BACK        Normal "next" pointers all implicitly point forward; BACK
  1281. X *        exists to make loop structures possible.
  1282. X *
  1283. X * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
  1284. X *        BRANCH structures using BACK.  Simple cases (one character
  1285. X *        per match) are implemented with STAR and PLUS for speed
  1286. X *        and to minimize recursive plunges.
  1287. X *
  1288. X * OPEN,CLOSE    ...are numbered at compile time.
  1289. X */
  1290. X
  1291. X/*
  1292. X * A node is one char of opcode followed by two chars of "next" pointer.
  1293. X * "Next" pointers are stored as two 8-bit pieces, high order first.  The
  1294. X * value is a positive offset from the opcode of the node containing it.
  1295. X * An operand, if any, simply follows the node.  (Note that much of the
  1296. X * code generation knows about this implicit relationship.)
  1297. X *
  1298. X * Using two bytes for the "next" pointer is vast overkill for most things,
  1299. X * but allows patterns to get big without disasters.
  1300. X */
  1301. X#define    OP(p)    (*(p))
  1302. X#define    NEXT(p)    (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
  1303. X#define    OPERAND(p)    ((p) + 3)
  1304. X
  1305. X/*
  1306. X * See regmagic.h for one further detail of program structure.
  1307. X */
  1308. X
  1309. X
  1310. X/*
  1311. X * Utility definitions.
  1312. X */
  1313. X#ifndef CHARBITS
  1314. X#define    UCHARAT(p)    ((int)*(unsigned char *)(p))
  1315. X#else
  1316. X#define    UCHARAT(p)    ((int)*(p)&CHARBITS)
  1317. X#endif
  1318. X
  1319. X#define    FAIL(m)    { regerror(m); return(NULL); }
  1320. X#define    ISMULT(c)    ((c) == '*' || (c) == '+' || (c) == '?')
  1321. X#define    META    "^$.[()|?+*\\"
  1322. X
  1323. X/*
  1324. X * Flags to be passed up and down.
  1325. X */
  1326. X#define    HASWIDTH    01    /* Known never to match null string. */
  1327. X#define    SIMPLE        02    /* Simple enough to be STAR/PLUS operand. */
  1328. X#define    SPSTART        04    /* Starts with * or +. */
  1329. X#define    WORST        0    /* Worst case. */
  1330. X
  1331. X/*
  1332. X * Global work variables for regcomp().
  1333. X */
  1334. Xstatic char *regparse;        /* Input-scan pointer. */
  1335. Xstatic int regnpar;        /* () count. */
  1336. Xstatic char regdummy;
  1337. Xstatic char *regcode;        /* Code-emit pointer; ®dummy = don't. */
  1338. Xstatic long regsize;        /* Code size. */
  1339. X#ifdef MULTILINE
  1340. Xstatic int regnl;        /* '\n' detected. */
  1341. X#endif
  1342. X
  1343. X/*
  1344. X * Forward declarations for regcomp()'s friends.
  1345. X */
  1346. X#ifndef STATIC
  1347. X#define    STATIC    static
  1348. X#endif
  1349. XSTATIC char *reg();
  1350. XSTATIC char *regbranch();
  1351. XSTATIC char *regpiece();
  1352. XSTATIC char *regatom();
  1353. XSTATIC char *regnode();
  1354. XSTATIC char *regnext();
  1355. XSTATIC void regc();
  1356. XSTATIC void reginsert();
  1357. XSTATIC void regtail();
  1358. XSTATIC void regoptail();
  1359. X#ifdef STRCSPN
  1360. XSTATIC int strcspn();
  1361. X#endif
  1362. X
  1363. X/*
  1364. X - regcomp - compile a regular expression into internal code
  1365. X *
  1366. X * We can't allocate space until we know how big the compiled form will be,
  1367. X * but we can't compile it (and thus know how big it is) until we've got a
  1368. X * place to put the code.  So we cheat:  we compile it twice, once with code
  1369. X * generation turned off and size counting turned on, and once "for real".
  1370. X * This also means that we don't allocate space until we are sure that the
  1371. X * thing really will compile successfully, and we never have to move the
  1372. X * code and thus invalidate pointers into it.  (Note that it has to be in
  1373. X * one piece because free() must be able to free it all.)
  1374. X *
  1375. X * Beware that the optimization-preparation code in here knows about some
  1376. X * of the structure of the compiled regexp.
  1377. X */
  1378. Xregexp *
  1379. Xregcomp(exp)
  1380. Xchar *exp;
  1381. X{
  1382. X    register regexp *r;
  1383. X    register char *scan;
  1384. X    register char *longest;
  1385. X    register int len;
  1386. X    int flags;
  1387. X
  1388. X    if (exp == NULL)
  1389. X        FAIL("NULL argument");
  1390. X
  1391. X    /* First pass: determine size, legality. */
  1392. X    regparse = exp;
  1393. X    regnpar = 1;
  1394. X    regsize = 0L;
  1395. X    regcode = ®dummy;
  1396. X#ifdef MULTILINE
  1397. X    regnl = 0;
  1398. X#endif
  1399. X    regc(MAGIC);
  1400. X    if (reg(0, &flags) == NULL)
  1401. X        return(NULL);
  1402. X
  1403. X    /* Small enough for pointer-storage convention? */
  1404. X    if (regsize >= 32767L)        /* Probably could be 65535L. */
  1405. X        FAIL("regexp too big");
  1406. X
  1407. X    /* Allocate space. */
  1408. X    r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
  1409. X    if (r == NULL)
  1410. X        FAIL("out of space");
  1411. X
  1412. X    /* Second pass: emit code. */
  1413. X    regparse = exp;
  1414. X    regnpar = 1;
  1415. X    regcode = r->program;
  1416. X    regc(MAGIC);
  1417. X    if (reg(0, &flags) == NULL)
  1418. X        return(NULL);
  1419. X
  1420. X    /* Dig out information for optimizations. */
  1421. X    r->regstart = '\0';    /* Worst-case defaults. */
  1422. X    r->reganch = 0;
  1423. X    r->regmust = NULL;
  1424. X    r->regmlen = 0;
  1425. X    scan = r->program+1;            /* First BRANCH. */
  1426. X    if (OP(regnext(scan)) == END) {        /* Only one top-level choice. */
  1427. X        scan = OPERAND(scan);
  1428. X
  1429. X        /* Starting-point info. */
  1430. X        if (OP(scan) == EXACTLY)
  1431. X            r->regstart = *OPERAND(scan);
  1432. X        else if (OP(scan) == BOL)
  1433. X            r->reganch++;
  1434. X
  1435. X        /*
  1436. X         * If there's something expensive in the r.e., find the
  1437. X         * longest literal string that must appear and make it the
  1438. X         * regmust.  Resolve ties in favor of later strings, since
  1439. X         * the regstart check works with the beginning of the r.e.
  1440. X         * and avoiding duplication strengthens checking.  Not a
  1441. X         * strong reason, but sufficient in the absence of others.
  1442. X         */
  1443. X#ifdef MULTILINE
  1444. X        if ((flags&SPSTART) && !regnl) {
  1445. X#else
  1446. X        if (flags&SPSTART) {
  1447. X#endif
  1448. X            longest = NULL;
  1449. X            len = 0;
  1450. X            for (; scan != NULL; scan = regnext(scan))
  1451. X                if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
  1452. X                    longest = OPERAND(scan);
  1453. X                    len = strlen(OPERAND(scan));
  1454. X                }
  1455. X            r->regmust = longest;
  1456. X            r->regmlen = len;
  1457. X        }
  1458. X    }
  1459. X
  1460. X    return(r);
  1461. X}
  1462. X
  1463. X/*
  1464. X - reg - regular expression, i.e. main body or parenthesized thing
  1465. X *
  1466. X * Caller must absorb opening parenthesis.
  1467. X *
  1468. X * Combining parenthesis handling with the base level of regular expression
  1469. X * is a trifle forced, but the need to tie the tails of the branches to what
  1470. X * follows makes it hard to avoid.
  1471. X */
  1472. Xstatic char *
  1473. Xreg(paren, flagp)
  1474. Xint paren;            /* Parenthesized? */
  1475. Xint *flagp;
  1476. X{
  1477. X    register char *ret;
  1478. X    register char *br;
  1479. X    register char *ender;
  1480. X    register int parno;
  1481. X    int flags;
  1482. X
  1483. X    *flagp = HASWIDTH;    /* Tentatively. */
  1484. X
  1485. X    /* Make an OPEN node, if parenthesized. */
  1486. X    if (paren) {
  1487. X        if (regnpar >= NSUBEXP)
  1488. X            FAIL("too many ()");
  1489. X        parno = regnpar;
  1490. X        regnpar++;
  1491. X        ret = regnode(OPEN+parno);
  1492. X    } else
  1493. X        ret = NULL;
  1494. X
  1495. X    /* Pick up the branches, linking them together. */
  1496. X    br = regbranch(&flags);
  1497. X    if (br == NULL)
  1498. X        return(NULL);
  1499. X    if (ret != NULL)
  1500. X        regtail(ret, br);    /* OPEN -> first. */
  1501. X    else
  1502. X        ret = br;
  1503. X    if (!(flags&HASWIDTH))
  1504. X        *flagp &= ~HASWIDTH;
  1505. X    *flagp |= flags&SPSTART;
  1506. X    while (*regparse == '|') {
  1507. X        regparse++;
  1508. X        br = regbranch(&flags);
  1509. X        if (br == NULL)
  1510. X            return(NULL);
  1511. X        regtail(ret, br);    /* BRANCH -> BRANCH. */
  1512. X        if (!(flags&HASWIDTH))
  1513. X            *flagp &= ~HASWIDTH;
  1514. X        *flagp |= flags&SPSTART;
  1515. X    }
  1516. X
  1517. X    /* Make a closing node, and hook it on the end. */
  1518. X    ender = regnode((paren) ? CLOSE+parno : END);    
  1519. X    regtail(ret, ender);
  1520. X
  1521. X    /* Hook the tails of the branches to the closing node. */
  1522. X    for (br = ret; br != NULL; br = regnext(br))
  1523. X        regoptail(br, ender);
  1524. X
  1525. X    /* Check for proper termination. */
  1526. X    if (paren && *regparse++ != ')') {
  1527. X        FAIL("unmatched ()");
  1528. X    } else if (!paren && *regparse != '\0') {
  1529. X        if (*regparse == ')') {
  1530. X            FAIL("unmatched ()");
  1531. X        } else
  1532. X            FAIL("junk on end");    /* "Can't happen". */
  1533. X        /* NOTREACHED */
  1534. X    }
  1535. X
  1536. X    return(ret);
  1537. X}
  1538. X
  1539. X/*
  1540. X - regbranch - one alternative of an | operator
  1541. X *
  1542. X * Implements the concatenation operator.
  1543. X */
  1544. Xstatic char *
  1545. Xregbranch(flagp)
  1546. Xint *flagp;
  1547. X{
  1548. X    register char *ret;
  1549. X    register char *chain;
  1550. X    register char *latest;
  1551. X    int flags;
  1552. X
  1553. X    *flagp = WORST;        /* Tentatively. */
  1554. X
  1555. X    ret = regnode(BRANCH);
  1556. X    chain = NULL;
  1557. X    while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
  1558. X        latest = regpiece(&flags);
  1559. X        if (latest == NULL)
  1560. X            return(NULL);
  1561. X        *flagp |= flags&HASWIDTH;
  1562. X        if (chain == NULL)    /* First piece. */
  1563. X            *flagp |= flags&SPSTART;
  1564. X        else
  1565. X            regtail(chain, latest);
  1566. X        chain = latest;
  1567. X    }
  1568. X    if (chain == NULL)    /* Loop ran zero times. */
  1569. X        (void) regnode(NOTHING);
  1570. X
  1571. X    return(ret);
  1572. X}
  1573. X
  1574. X/*
  1575. X - regpiece - something followed by possible [*+?]
  1576. X *
  1577. X * Note that the branching code sequences used for ? and the general cases
  1578. X * of * and + are somewhat optimized:  they use the same NOTHING node as
  1579. X * both the endmarker for their branch list and the body of the last branch.
  1580. X * It might seem that this node could be dispensed with entirely, but the
  1581. X * endmarker role is not redundant.
  1582. X */
  1583. Xstatic char *
  1584. Xregpiece(flagp)
  1585. Xint *flagp;
  1586. X{
  1587. X    register char *ret;
  1588. X    register char op;
  1589. X    register char *next;
  1590. X    int flags;
  1591. X
  1592. X    ret = regatom(&flags);
  1593. X    if (ret == NULL)
  1594. X        return(NULL);
  1595. X
  1596. X    op = *regparse;
  1597. X    if (!ISMULT(op)) {
  1598. X        *flagp = flags;
  1599. X        return(ret);
  1600. X    }
  1601. X
  1602. X    if (!(flags&HASWIDTH) && op != '?')
  1603. X        FAIL("*+ operand could be empty");
  1604. X    *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
  1605. X
  1606. X    if (op == '*' && (flags&SIMPLE))
  1607. X        reginsert(STAR, ret);
  1608. X    else if (op == '*') {
  1609. X        /* Emit x* as (x&|), where & means "self". */
  1610. X        reginsert(BRANCH, ret);            /* Either x */
  1611. X        regoptail(ret, regnode(BACK));        /* and loop */
  1612. X        regoptail(ret, ret);            /* back */
  1613. X        regtail(ret, regnode(BRANCH));        /* or */
  1614. X        regtail(ret, regnode(NOTHING));        /* null. */
  1615. X    } else if (op == '+' && (flags&SIMPLE))
  1616. X        reginsert(PLUS, ret);
  1617. X    else if (op == '+') {
  1618. X        /* Emit x+ as x(&|), where & means "self". */
  1619. X        next = regnode(BRANCH);            /* Either */
  1620. X        regtail(ret, next);
  1621. X        regtail(regnode(BACK), ret);        /* loop back */
  1622. X        regtail(next, regnode(BRANCH));        /* or */
  1623. X        regtail(ret, regnode(NOTHING));        /* null. */
  1624. X    } else if (op == '?') {
  1625. X        /* Emit x? as (x|) */
  1626. X        reginsert(BRANCH, ret);            /* Either x */
  1627. X        regtail(ret, regnode(BRANCH));        /* or */
  1628. X        next = regnode(NOTHING);        /* null. */
  1629. X        regtail(ret, next);
  1630. X        regoptail(ret, next);
  1631. X    }
  1632. X    regparse++;
  1633. X    if (ISMULT(*regparse))
  1634. X        FAIL("nested *?+");
  1635. X
  1636. X    return(ret);
  1637. X}
  1638. X
  1639. X/*
  1640. X - regatom - the lowest level
  1641. X *
  1642. X * Optimization:  gobbles an entire sequence of ordinary characters so that
  1643. X * it can turn them into a single node, which is smaller to store and
  1644. X * faster to run.  Backslashed characters are exceptions, each becoming a
  1645. X * separate node; the code is simpler that way and it's not worth fixing.
  1646. X */
  1647. Xstatic char *
  1648. Xregatom(flagp)
  1649. Xint *flagp;
  1650. X{
  1651. X    register char *ret;
  1652. X    int flags;
  1653. X
  1654. X    *flagp = WORST;        /* Tentatively. */
  1655. X
  1656. X    switch (*regparse++) {
  1657. X    case '^':
  1658. X        ret = regnode(BOL);
  1659. X        break;
  1660. X    case '$':
  1661. X        ret = regnode(EOL);
  1662. X        break;
  1663. X    case '.':
  1664. X        ret = regnode(ANY);
  1665. X        *flagp |= HASWIDTH|SIMPLE;
  1666. X        break;
  1667. X    case '[': {
  1668. X            register int class;
  1669. X            register int classend;
  1670. X
  1671. X            if (*regparse == '^') {    /* Complement of range. */
  1672. X                ret = regnode(ANYBUT);
  1673. X                regparse++;
  1674. X            } else
  1675. X                ret = regnode(ANYOF);
  1676. X            if (*regparse == ']' || *regparse == '-')
  1677. X                regc(*regparse++);
  1678. X            while (*regparse != '\0' && *regparse != ']') {
  1679. X                if (*regparse == '-') {
  1680. X                    regparse++;
  1681. X                    if (*regparse == ']' || *regparse == '\0')
  1682. X                        regc('-');
  1683. X                    else {
  1684. X                        class = UCHARAT(regparse-2)+1;
  1685. X                        classend = UCHARAT(regparse);
  1686. X                        if (class > classend+1)
  1687. X                            FAIL("invalid [] range");
  1688. X                        for (; class <= classend; class++)
  1689. X                            regc(class);
  1690. X                        regparse++;
  1691. X                    }
  1692. X                } else
  1693. X                    regc(*regparse++);
  1694. X            }
  1695. X            regc('\0');
  1696. X            if (*regparse != ']')
  1697. X                FAIL("unmatched []");
  1698. X            regparse++;
  1699. X            *flagp |= HASWIDTH|SIMPLE;
  1700. X        }
  1701. X        break;
  1702. X    case '(':
  1703. X        ret = reg(1, &flags);
  1704. X        if (ret == NULL)
  1705. X            return(NULL);
  1706. X        *flagp |= flags&(HASWIDTH|SPSTART);
  1707. X        break;
  1708. X    case '\0':
  1709. X    case '|':
  1710. X    case ')':
  1711. X        FAIL("internal urp");    /* Supposed to be caught earlier. */
  1712. X        break;
  1713. X    case '?':
  1714. X    case '+':
  1715. X    case '*':
  1716. X        FAIL("?+* follows nothing");
  1717. X        break;
  1718. X    case '\\':
  1719. X        if (*regparse == '\0')
  1720. X            FAIL("trailing \\");
  1721. X        ret = regnode(EXACTLY);
  1722. X#ifdef MULTILINE
  1723. X        if (*regparse == 'n') {
  1724. X            regc('\n');
  1725. X            regparse++;
  1726. X            regnl++;
  1727. X        }
  1728. X        else
  1729. X#endif
  1730. X        regc(*regparse++);
  1731. X        regc('\0');
  1732. X        *flagp |= HASWIDTH|SIMPLE;
  1733. X        break;
  1734. X    default: {
  1735. X            register int len;
  1736. X            register char ender;
  1737. X
  1738. X            regparse--;
  1739. X            len = strcspn(regparse, META);
  1740. X            if (len <= 0)
  1741. X                FAIL("internal disaster");
  1742. X            ender = *(regparse+len);
  1743. X            if (len > 1 && ISMULT(ender))
  1744. X                len--;        /* Back off clear of ?+* operand. */
  1745. X            *flagp |= HASWIDTH;
  1746. X            if (len == 1)
  1747. X                *flagp |= SIMPLE;
  1748. X            ret = regnode(EXACTLY);
  1749. X            while (len > 0) {
  1750. X#ifdef MULTILINE
  1751. X                if (*regparse == '\n')
  1752. X                    regnl++;
  1753. X#endif
  1754. X                regc(*regparse++);
  1755. X                len--;
  1756. X            }
  1757. X            regc('\0');
  1758. X        }
  1759. X        break;
  1760. X    }
  1761. X
  1762. X    return(ret);
  1763. X}
  1764. X
  1765. X/*
  1766. X - regnode - emit a node
  1767. X */
  1768. Xstatic char *            /* Location. */
  1769. Xregnode(op)
  1770. Xchar op;
  1771. X{
  1772. X    register char *ret;
  1773. X    register char *ptr;
  1774. X
  1775. X    ret = regcode;
  1776. X    if (ret == ®dummy) {
  1777. X        regsize += 3;
  1778. X        return(ret);
  1779. X    }
  1780. X
  1781. X    ptr = ret;
  1782. X    *ptr++ = op;
  1783. X    *ptr++ = '\0';        /* Null "next" pointer. */
  1784. X    *ptr++ = '\0';
  1785. X    regcode = ptr;
  1786. X
  1787. X    return(ret);
  1788. X}
  1789. X
  1790. X/*
  1791. X - regc - emit (if appropriate) a byte of code
  1792. X */
  1793. Xstatic void
  1794. Xregc(b)
  1795. Xchar b;
  1796. X{
  1797. X    if (regcode != ®dummy)
  1798. X        *regcode++ = b;
  1799. X    else
  1800. X        regsize++;
  1801. X}
  1802. X
  1803. X/*
  1804. X - reginsert - insert an operator in front of already-emitted operand
  1805. X *
  1806. X * Means relocating the operand.
  1807. X */
  1808. Xstatic void
  1809. Xreginsert(op, opnd)
  1810. Xchar op;
  1811. Xchar *opnd;
  1812. X{
  1813. X    register char *src;
  1814. X    register char *dst;
  1815. X    register char *place;
  1816. X
  1817. X    if (regcode == ®dummy) {
  1818. X        regsize += 3;
  1819. X        return;
  1820. X    }
  1821. X
  1822. X    src = regcode;
  1823. X    regcode += 3;
  1824. X    dst = regcode;
  1825. X    while (src > opnd)
  1826. X        *--dst = *--src;
  1827. X
  1828. X    place = opnd;        /* Op node, where operand used to be. */
  1829. X    *place++ = op;
  1830. X    *place++ = '\0';
  1831. X    *place++ = '\0';
  1832. X}
  1833. X
  1834. X/*
  1835. X - regtail - set the next-pointer at the end of a node chain
  1836. X */
  1837. Xstatic void
  1838. Xregtail(p, val)
  1839. Xchar *p;
  1840. Xchar *val;
  1841. X{
  1842. X    register char *scan;
  1843. X    register char *temp;
  1844. X    register int offset;
  1845. X
  1846. X    if (p == ®dummy)
  1847. X        return;
  1848. X
  1849. X    /* Find last node. */
  1850. X    scan = p;
  1851. X    for (;;) {
  1852. X        temp = regnext(scan);
  1853. X        if (temp == NULL)
  1854. X            break;
  1855. X        scan = temp;
  1856. X    }
  1857. X
  1858. X    if (OP(scan) == BACK)
  1859. X        offset = scan - val;
  1860. X    else
  1861. X        offset = val - scan;
  1862. X    *(scan+1) = (offset>>8)&0377;
  1863. X    *(scan+2) = offset&0377;
  1864. X}
  1865. X
  1866. X/*
  1867. X - regoptail - regtail on operand of first argument; nop if operandless
  1868. X */
  1869. Xstatic void
  1870. Xregoptail(p, val)
  1871. Xchar *p;
  1872. Xchar *val;
  1873. X{
  1874. X    /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  1875. X    if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  1876. X        return;
  1877. X    regtail(OPERAND(p), val);
  1878. X}
  1879. X
  1880. X/*
  1881. X * regexec and friends
  1882. X */
  1883. X
  1884. X/*
  1885. X * Global work variables for regexec().
  1886. X */
  1887. Xstatic char *reginput;        /* String-input pointer. */
  1888. Xstatic char *regbol;        /* Beginning of input, for ^ check. */
  1889. Xstatic char **regstartp;    /* Pointer to startp array. */
  1890. Xstatic char **regendp;        /* Ditto for endp. */
  1891. X
  1892. X/*
  1893. X * Forwards.
  1894. X */
  1895. XSTATIC int regtry();
  1896. XSTATIC int regmatch();
  1897. XSTATIC int regrepeat();
  1898. X
  1899. X#ifdef DEBUG
  1900. Xint regnarrate = 0;
  1901. Xvoid regdump();
  1902. XSTATIC char *regprop();
  1903. X#endif
  1904. X
  1905. X/*
  1906. X - regexec - match a regexp against a string
  1907. X */
  1908. Xint
  1909. Xregexec(prog, string)
  1910. Xregister regexp *prog;
  1911. Xregister char *string;
  1912. X{
  1913. X    register char *s;
  1914. X    extern char *strchr();
  1915. X
  1916. X    /* Be paranoid... */
  1917. X    if (prog == NULL || string == NULL) {
  1918. X        regerror("NULL parameter");
  1919. X        return(0);
  1920. X    }
  1921. X
  1922. X#ifdef MULTILINE
  1923. X    /* Check for \n in string, and if so, call the more general routine. */
  1924. X    if (strchr(string, '\n') != NULL)
  1925. X        return reglexec(prog, string, 0);
  1926. X#endif
  1927. X
  1928. X    /* Check validity of program. */
  1929. X    if (UCHARAT(prog->program) != MAGIC) {
  1930. X        regerror("corrupted program");
  1931. X        return(0);
  1932. X    }
  1933. X
  1934. X    /* If there is a "must appear" string, look for it. */
  1935. X    if (prog->regmust != NULL) {
  1936. X        s = string;
  1937. X        while ((s = strchr(s, prog->regmust[0])) != NULL) {
  1938. X            if (strncmp(s, prog->regmust, prog->regmlen) == 0)
  1939. X                break;    /* Found it. */
  1940. X            s++;
  1941. X        }
  1942. X        if (s == NULL)    /* Not present. */
  1943. X            return(0);
  1944. X    }
  1945. X
  1946. X    /* Mark beginning of line for ^ . */
  1947. X    regbol = string;
  1948. X
  1949. X    /* Simplest case:  anchored match need be tried only once. */
  1950. X    if (prog->reganch)
  1951. X        return(regtry(prog, string));
  1952. X
  1953. X    /* Messy cases:  unanchored match. */
  1954. X    s = string;
  1955. X    if (prog->regstart != '\0')
  1956. X        /* We know what char it must start with. */
  1957. X        while ((s = strchr(s, prog->regstart)) != NULL) {
  1958. X            if (regtry(prog, s))
  1959. X                return(1);
  1960. X            s++;
  1961. X        }
  1962. X    else
  1963. X        /* We don't -- general case. */
  1964. X        do {
  1965. X            if (regtry(prog, s))
  1966. X                return(1);
  1967. X        } while (*s++ != '\0');
  1968. X
  1969. X    /* Failure. */
  1970. X    return(0);
  1971. X}
  1972. X
  1973. X#ifdef MULTILINE
  1974. X/*
  1975. X - reglexec - match a regexp against a long string buffer, starting at offset
  1976. X */
  1977. Xint
  1978. Xreglexec(prog, string, offset)
  1979. Xregister regexp *prog;
  1980. Xregister char *string;
  1981. X{
  1982. X    register char *s;
  1983. X    extern char *strchr();
  1984. X
  1985. X    /* Be paranoid... */
  1986. X    if (prog == NULL || string == NULL) {
  1987. X        regerror("NULL parameter");
  1988. X        return(0);
  1989. X    }
  1990. X
  1991. X    /* Check validity of program. */
  1992. X    if (UCHARAT(prog->program) != MAGIC) {
  1993. X        regerror("corrupted program");
  1994. X        return(0);
  1995. X    }
  1996. X
  1997. X    /* (Don't look for "must appear" string -- string can be long.) */
  1998. X
  1999. X    /* Mark beginning of line for ^ . */
  2000. X    regbol = string;
  2001. X    
  2002. X    /* Apply offset.
  2003. X       Assume 0 <= offset <= strlen(string), but don't check,
  2004. X       as string can be long. */
  2005. X    s= string + offset;
  2006. X
  2007. X    /* Anchored match need be tried only at line starts. */
  2008. X    if (prog->reganch) {
  2009. X        while (!regtry(prog, s)) {
  2010. X            s = strchr(s, '\n');
  2011. X            if (s == NULL)
  2012. X                return(0);
  2013. X            s++;
  2014. X        }
  2015. X        return(1);
  2016. X    }
  2017. X
  2018. X    /* Messy cases:  unanchored match. */
  2019. X    if (prog->regstart != '\0')
  2020. X        /* We know what char it must start with. */
  2021. X        while ((s = strchr(s, prog->regstart)) != NULL) {
  2022. X            if (regtry(prog, s))
  2023. X                return(1);
  2024. X            s++;
  2025. X        }
  2026. X    else
  2027. X        /* We don't -- general case. */
  2028. X        do {
  2029. X            if (regtry(prog, s))
  2030. X                return(1);
  2031. X        } while (*s++ != '\0');
  2032. X
  2033. X    /* Failure. */
  2034. X    return(0);
  2035. X}
  2036. X#endif
  2037. X
  2038. X/*
  2039. X - regtry - try match at specific point
  2040. X */
  2041. Xstatic int            /* 0 failure, 1 success */
  2042. Xregtry(prog, string)
  2043. Xregexp *prog;
  2044. Xchar *string;
  2045. X{
  2046. X    register int i;
  2047. X    register char **sp;
  2048. X    register char **ep;
  2049. X
  2050. X    reginput = string;
  2051. X    regstartp = prog->startp;
  2052. X    regendp = prog->endp;
  2053. X
  2054. X    sp = prog->startp;
  2055. X    ep = prog->endp;
  2056. X    for (i = NSUBEXP; i > 0; i--) {
  2057. X        *sp++ = NULL;
  2058. X        *ep++ = NULL;
  2059. X    }
  2060. X    if (regmatch(prog->program + 1)) {
  2061. X        prog->startp[0] = string;
  2062. X        prog->endp[0] = reginput;
  2063. X        return(1);
  2064. X    } else
  2065. X        return(0);
  2066. X}
  2067. X
  2068. X/*
  2069. X - regmatch - main matching routine
  2070. X *
  2071. X * Conceptually the strategy is simple:  check to see whether the current
  2072. X * node matches, call self recursively to see whether the rest matches,
  2073. X * and then act accordingly.  In practice we make some effort to avoid
  2074. X * recursion, in particular by going through "ordinary" nodes (that don't
  2075. X * need to know whether the rest of the match failed) by a loop instead of
  2076. X * by recursion.
  2077. X */
  2078. Xstatic int            /* 0 failure, 1 success */
  2079. Xregmatch(prog)
  2080. Xchar *prog;
  2081. X{
  2082. X    register char *scan;    /* Current node. */
  2083. X    char *next;        /* Next node. */
  2084. X    extern char *strchr();
  2085. X
  2086. X    scan = prog;
  2087. X#ifdef DEBUG
  2088. X    if (scan != NULL && regnarrate)
  2089. X        fprintf(stderr, "%s(\n", regprop(scan));
  2090. X#endif
  2091. X    while (scan != NULL) {
  2092. X#ifdef DEBUG
  2093. X        if (regnarrate)
  2094. X            fprintf(stderr, "%s...\n", regprop(scan));
  2095. X#endif
  2096. X        next = regnext(scan);
  2097. X
  2098. X        switch (OP(scan)) {
  2099. X        case BOL:
  2100. X#ifdef MULTILINE
  2101. X            if (!(reginput == regbol ||
  2102. X                reginput > regbol && *(reginput-1) == '\n'))
  2103. X#else
  2104. X            if (reginput != regbol)
  2105. X#endif
  2106. X                return(0);
  2107. X            break;
  2108. X        case EOL:
  2109. X#ifdef MULTILINE
  2110. X            if (*reginput != '\0' && *reginput != '\n')
  2111. X#else
  2112. X            if (*reginput != '\0')
  2113. X#endif
  2114. X                return(0);
  2115. X            break;
  2116. X        case ANY:
  2117. X#ifdef MULTILINE
  2118. X            if (*reginput == '\0' || *reginput == '\n')
  2119. X#else
  2120. X            if (*reginput == '\0')
  2121. X#endif
  2122. X                return(0);
  2123. X            reginput++;
  2124. X            break;
  2125. X        case EXACTLY: {
  2126. X                register int len;
  2127. X                register char *opnd;
  2128. X
  2129. X                opnd = OPERAND(scan);
  2130. X                /* Inline the first character, for speed. */
  2131. X                if (*opnd != *reginput)
  2132. X                    return(0);
  2133. X                len = strlen(opnd);
  2134. X                if (len > 1 && strncmp(opnd, reginput, len) != 0)
  2135. X                    return(0);
  2136. X                reginput += len;
  2137. X            }
  2138. X            break;
  2139. X        case ANYOF:
  2140. X            if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
  2141. X                return(0);
  2142. X            reginput++;
  2143. X            break;
  2144. X        case ANYBUT:
  2145. X#ifdef MULTILINE
  2146. X            if (*reginput == '\0' || *reginput == '\n' ||
  2147. X                strchr(OPERAND(scan), *reginput) != NULL)
  2148. X#else
  2149. X            if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
  2150. X#endif
  2151. X                return(0);
  2152. X            reginput++;
  2153. X            break;
  2154. X        case NOTHING:
  2155. X            break;
  2156. X        case BACK:
  2157. X            break;
  2158. X        case OPEN+1:
  2159. X        case OPEN+2:
  2160. X        case OPEN+3:
  2161. X        case OPEN+4:
  2162. X        case OPEN+5:
  2163. X        case OPEN+6:
  2164. X        case OPEN+7:
  2165. X        case OPEN+8:
  2166. X        case OPEN+9: {
  2167. X                register int no;
  2168. X                register char *save;
  2169. X
  2170. X                no = OP(scan) - OPEN;
  2171. X                save = reginput;
  2172. X
  2173. X                if (regmatch(next)) {
  2174. X                    /*
  2175. X                     * Don't set startp if some later
  2176. X                     * invocation of the same parentheses
  2177. X                     * already has.
  2178. X                     */
  2179. X                    if (regstartp[no] == NULL)
  2180. X                        regstartp[no] = save;
  2181. X                    return(1);
  2182. X                } else
  2183. X                    return(0);
  2184. X            }
  2185. X            break;
  2186. X        case CLOSE+1:
  2187. X        case CLOSE+2:
  2188. X        case CLOSE+3:
  2189. X        case CLOSE+4:
  2190. X        case CLOSE+5:
  2191. X        case CLOSE+6:
  2192. X        case CLOSE+7:
  2193. X        case CLOSE+8:
  2194. X        case CLOSE+9: {
  2195. X                register int no;
  2196. X                register char *save;
  2197. X
  2198. X                no = OP(scan) - CLOSE;
  2199. X                save = reginput;
  2200. X
  2201. X                if (regmatch(next)) {
  2202. X                    /*
  2203. X                     * Don't set endp if some later
  2204. X                     * invocation of the same parentheses
  2205. X                     * already has.
  2206. X                     */
  2207. X                    if (regendp[no] == NULL)
  2208. X                        regendp[no] = save;
  2209. X                    return(1);
  2210. X                } else
  2211. X                    return(0);
  2212. X            }
  2213. X            break;
  2214. X        case BRANCH: {
  2215. X                register char *save;
  2216. X
  2217. X                if (OP(next) != BRANCH)        /* No choice. */
  2218. X                    next = OPERAND(scan);    /* Avoid recursion. */
  2219. X                else {
  2220. X                    do {
  2221. X                        save = reginput;
  2222. X                        if (regmatch(OPERAND(scan)))
  2223. X                            return(1);
  2224. X                        reginput = save;
  2225. X                        scan = regnext(scan);
  2226. X                    } while (scan != NULL && OP(scan) == BRANCH);
  2227. X                    return(0);
  2228. X                    /* NOTREACHED */
  2229. X                }
  2230. X            }
  2231. X            break;
  2232. X        case STAR:
  2233. X        case PLUS: {
  2234. X                register char nextch;
  2235. X                register int no;
  2236. X                register char *save;
  2237. X                register int min;
  2238. X
  2239. X                /*
  2240. X                 * Lookahead to avoid useless match attempts
  2241. X                 * when we know what character comes next.
  2242. X                 */
  2243. X                nextch = '\0';
  2244. X                if (OP(next) == EXACTLY)
  2245. X                    nextch = *OPERAND(next);
  2246. X                min = (OP(scan) == STAR) ? 0 : 1;
  2247. X                save = reginput;
  2248. X                no = regrepeat(OPERAND(scan));
  2249. X                while (no >= min) {
  2250. X                    /* If it could work, try it. */
  2251. X                    if (nextch == '\0' || *reginput == nextch)
  2252. X                        if (regmatch(next))
  2253. X                            return(1);
  2254. X                    /* Couldn't or didn't -- back up. */
  2255. X                    no--;
  2256. X                    reginput = save + no;
  2257. X                }
  2258. X                return(0);
  2259. X            }
  2260. X            break;
  2261. X        case END:
  2262. X            return(1);    /* Success! */
  2263. X            break;
  2264. X        default:
  2265. X            regerror("memory corruption");
  2266. X            return(0);
  2267. X            break;
  2268. X        }
  2269. X
  2270. X        scan = next;
  2271. X    }
  2272. X
  2273. X    /*
  2274. X     * We get here only if there's trouble -- normally "case END" is
  2275. X     * the terminating point.
  2276. X     */
  2277. X    regerror("corrupted pointers");
  2278. X    return(0);
  2279. X}
  2280. X
  2281. X/*
  2282. X - regrepeat - repeatedly match something simple, report how many
  2283. X */
  2284. Xstatic int
  2285. Xregrepeat(p)
  2286. Xchar *p;
  2287. X{
  2288. X    register int count = 0;
  2289. X    register char *scan;
  2290. X    register char *opnd;
  2291. X#ifdef MULTILINE
  2292. X    register char *eol;
  2293. X#endif
  2294. X
  2295. X    scan = reginput;
  2296. X    opnd = OPERAND(p);
  2297. X    switch (OP(p)) {
  2298. X    case ANY:
  2299. X#ifdef MULTILINE
  2300. X        if ((eol = strchr(scan, '\n')) != NULL) {
  2301. X            count += eol - scan;
  2302. X            scan = eol;
  2303. X            break;
  2304. X        }
  2305. X#endif
  2306. X        count = strlen(scan);
  2307. X        scan += count;
  2308. X        break;
  2309. X    case EXACTLY:
  2310. X        while (*opnd == *scan) {
  2311. X            count++;
  2312. X            scan++;
  2313. X        }
  2314. X        break;
  2315. X    case ANYOF:
  2316. X        while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
  2317. X            count++;
  2318. X            scan++;
  2319. X        }
  2320. X        break;
  2321. X    case ANYBUT:
  2322. X#ifdef MULTILINE
  2323. X        while (*scan != '\0' && *scan != '\n' &&
  2324. X            strchr(opnd, *scan) == NULL) {
  2325. X#else
  2326. X        while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
  2327. X#endif
  2328. X            count++;
  2329. X            scan++;
  2330. X        }
  2331. X        break;
  2332. X    default:        /* Oh dear.  Called inappropriately. */
  2333. X        regerror("internal foulup");
  2334. X        count = 0;    /* Best compromise. */
  2335. X        break;
  2336. X    }
  2337. X    reginput = scan;
  2338. X
  2339. X    return(count);
  2340. X}
  2341. X
  2342. X/*
  2343. X - regnext - dig the "next" pointer out of a node
  2344. X */
  2345. Xstatic char *
  2346. Xregnext(p)
  2347. Xregister char *p;
  2348. X{
  2349. X    register int offset;
  2350. X
  2351. X    if (p == ®dummy)
  2352. X        return(NULL);
  2353. X
  2354. X    offset = NEXT(p);
  2355. X    if (offset == 0)
  2356. X        return(NULL);
  2357. X
  2358. X    if (OP(p) == BACK)
  2359. X        return(p-offset);
  2360. X    else
  2361. X        return(p+offset);
  2362. X}
  2363. X
  2364. X#ifdef DEBUG
  2365. X
  2366. XSTATIC char *regprop();
  2367. X
  2368. X/*
  2369. X - regdump - dump a regexp onto stdout in vaguely comprehensible form
  2370. X */
  2371. Xvoid
  2372. Xregdump(r)
  2373. Xregexp *r;
  2374. X{
  2375. X    register char *s;
  2376. X    register char op = EXACTLY;    /* Arbitrary non-END op. */
  2377. X    register char *next;
  2378. X    extern char *strchr();
  2379. X
  2380. X
  2381. X    s = r->program + 1;
  2382. X    while (op != END) {    /* While that wasn't END last time... */
  2383. X        op = OP(s);
  2384. X        printf("%2d%s", (int)(s-r->program), regprop(s));    /* Where, what. */
  2385. X        next = regnext(s);
  2386. X        if (next == NULL)        /* Next ptr. */
  2387. X            printf("(0)");
  2388. X        else 
  2389. X            printf("(%d)", (int)((s-r->program)+(next-s)));
  2390. X        s += 3;
  2391. X        if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
  2392. X            /* Literal string, where present. */
  2393. X            while (*s != '\0') {
  2394. X#ifdef MULTILINE
  2395. X                if (*s == '\n')
  2396. X                    printf("\\n");
  2397. X                else
  2398. X#endif
  2399. X                putchar(*s);
  2400. X                s++;
  2401. X            }
  2402. X            s++;
  2403. X        }
  2404. X        putchar('\n');
  2405. X    }
  2406. X
  2407. X    /* Header fields of interest. */
  2408. X    if (r->regstart != '\0')
  2409. X        printf("start `%c' ", r->regstart);
  2410. X    if (r->reganch)
  2411. X        printf("anchored ");
  2412. X    if (r->regmust != NULL)
  2413. X        printf("must have \"%s\"", r->regmust);
  2414. X    printf("\n");
  2415. X}
  2416. X
  2417. X/*
  2418. X - regprop - printable representation of opcode
  2419. X */
  2420. Xstatic char *
  2421. Xregprop(op)
  2422. Xchar *op;
  2423. X{
  2424. X    register char *p;
  2425. X    static char buf[50];
  2426. X
  2427. X    (void) strcpy(buf, ":");
  2428. X
  2429. X    switch (OP(op)) {
  2430. X    case BOL:
  2431. X        p = "BOL";
  2432. X        break;
  2433. X    case EOL:
  2434. X        p = "EOL";
  2435. X        break;
  2436. X    case ANY:
  2437. X        p = "ANY";
  2438. X        break;
  2439. X    case ANYOF:
  2440. X        p = "ANYOF";
  2441. X        break;
  2442. X    case ANYBUT:
  2443. X        p = "ANYBUT";
  2444. X        break;
  2445. X    case BRANCH:
  2446. X        p = "BRANCH";
  2447. X        break;
  2448. X    case EXACTLY:
  2449. X        p = "EXACTLY";
  2450. X        break;
  2451. X    case NOTHING:
  2452. X        p = "NOTHING";
  2453. X        break;
  2454. X    case BACK:
  2455. X        p = "BACK";
  2456. X        break;
  2457. X    case END:
  2458. X        p = "END";
  2459. X        break;
  2460. X    case OPEN+1:
  2461. X    case OPEN+2:
  2462. X    case OPEN+3:
  2463. X    case OPEN+4:
  2464. X    case OPEN+5:
  2465. X    case OPEN+6:
  2466. X    case OPEN+7:
  2467. X    case OPEN+8:
  2468. X    case OPEN+9:
  2469. X        sprintf(buf+strlen(buf), "OPEN%d", (int)(OP(op)-OPEN));
  2470. X        p = NULL;
  2471. X        break;
  2472. X    case CLOSE+1:
  2473. X    case CLOSE+2:
  2474. X    case CLOSE+3:
  2475. X    case CLOSE+4:
  2476. X    case CLOSE+5:
  2477. X    case CLOSE+6:
  2478. X    case CLOSE+7:
  2479. X    case CLOSE+8:
  2480. X    case CLOSE+9:
  2481. X        sprintf(buf+strlen(buf), "CLOSE%d", (int)(OP(op)-CLOSE));
  2482. X        p = NULL;
  2483. X        break;
  2484. X    case STAR:
  2485. X        p = "STAR";
  2486. X        break;
  2487. X    case PLUS:
  2488. X        p = "PLUS";
  2489. X        break;
  2490. X    default:
  2491. X        regerror("corrupted opcode");
  2492. X        break;
  2493. X    }
  2494. X    if (p != NULL)
  2495. X        (void) strcat(buf, p);
  2496. X    return(buf);
  2497. X}
  2498. X#endif
  2499. X
  2500. X/*
  2501. X * The following is provided for those people who do not have strcspn() in
  2502. X * their C libraries.  They should get off their butts and do something
  2503. X * about it; at least one public-domain implementation of those (highly
  2504. X * useful) string routines has been published on Usenet.
  2505. X */
  2506. X#ifdef STRCSPN
  2507. X/*
  2508. X * strcspn - find length of initial segment of s1 consisting entirely
  2509. X * of characters not from s2
  2510. X */
  2511. X
  2512. Xstatic int
  2513. Xstrcspn(s1, s2)
  2514. Xchar *s1;
  2515. Xchar *s2;
  2516. X{
  2517. X    register char *scan1;
  2518. X    register char *scan2;
  2519. X    register int count;
  2520. X
  2521. X    count = 0;
  2522. X    for (scan1 = s1; *scan1 != '\0'; scan1++) {
  2523. X        for (scan2 = s2; *scan2 != '\0';)    /* ++ moved down. */
  2524. X            if (*scan1 == *scan2++)
  2525. X                return(count);
  2526. X        count++;
  2527. X    }
  2528. X    return(count);
  2529. X}
  2530. X#endif
  2531. EOF
  2532. fi
  2533. echo 'Part 05 out of 21 of pack.out complete.'
  2534. exit 0
  2535.