home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / sources / misc / 4171 < prev    next >
Encoding:
Text File  |  1992-12-13  |  57.2 KB  |  1,908 lines

  1. Newsgroups: comp.sources.misc
  2. Path: sparky!kent
  3. From: cristy@eplrx7.es.duPont.com (John Cristy)
  4. Subject:  v34i031:  imagemagick - X11 image processing and display v2.2, Part03/26
  5. Message-ID: <1992Dec13.202349.7975@sparky.imd.sterling.com>
  6. Followup-To: comp.sources.d
  7. X-Md4-Signature: dcedf45d348e8c1204f2200228373068
  8. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  9. Organization: Sterling Software
  10. References: <csm-v34i028=imagemagick.141926@sparky.IMD.Sterling.COM>
  11. Date: Sun, 13 Dec 1992 20:23:49 GMT
  12. Approved: kent@sparky.imd.sterling.com
  13. Lines: 1893
  14.  
  15. Submitted-by: cristy@eplrx7.es.duPont.com (John Cristy)
  16. Posting-number: Volume 34, Issue 31
  17. Archive-name: imagemagick/part03
  18. Environment: UNIX, VMS, X11, SGI, DEC, Cray, Sun, Vax
  19.  
  20. #!/bin/sh
  21. # this is Part.03 (part 3 of a multipart archive)
  22. # do not concatenate these parts, unpack them in order with /bin/sh
  23. # file ImageMagick/xtp/regular.c continued
  24. #
  25. if test ! -r _shar_seq_.tmp; then
  26.     echo 'Please unpack part 1 first!'
  27.     exit 1
  28. fi
  29. (read Scheck
  30.  if test "$Scheck" != 3; then
  31.     echo Please unpack part "$Scheck" next!
  32.     exit 1
  33.  else
  34.     exit 0
  35.  fi
  36. ) < _shar_seq_.tmp || exit 1
  37. if test ! -f _shar_wnt_.tmp; then
  38.     echo 'x - still skipping ImageMagick/xtp/regular.c'
  39. else
  40. echo 'x - continuing file ImageMagick/xtp/regular.c'
  41. sed 's/^X//' << 'SHAR_EOF' >> 'ImageMagick/xtp/regular.c' &&
  42. %  & Company not be used in advertising or publicity pertaining to            %
  43. %  distribution of the software without specific, written prior               %
  44. %  permission.  E. I. Dupont de Nemours & Company makes no representations    %
  45. %  about the suitability of this software for any purpose.  It is provided    %
  46. %  "as is" without express or implied warranty.                               %
  47. %                                                                             %
  48. %  E. I. Dupont de Nemours & Company disclaims all warranties with regard     %
  49. %  to this software, including all implied warranties of merchantability      %
  50. %  and fitness, in no event shall E. I. Dupont de Nemours & Company be        %
  51. %  liable for any special, indirect or consequential damages or any           %
  52. %  damages whatsoever resulting from loss of use, data or profits, whether    %
  53. %  in an action of contract, negligence or other tortious action, arising     %
  54. %  out of or in connection with the use or performance of this software.      %
  55. %                                                                             %
  56. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  57. %
  58. %  CompileRegularExpression returns NULL for a failure, where failures are
  59. %  syntax errors, exceeding implementation limits, or applying `+' or `*'
  60. %  to a possibly-null operand.
  61. %
  62. %  This is essentially the same routine written and copywrited by Henry
  63. %  Spencer, University of Toronto.  I made minor programming changes but
  64. %  major variable name changes to improve readability.
  65. %
  66. %  A regular expression is zero or more branches, separated by `|'. It
  67. %  matches anything that matches one of the branches.
  68. %
  69. %  A branch is zero or more pieces, concatenated. It matches a match for
  70. %  the first, followed by a match for the second, etc.
  71. %
  72. %  A piece is an atom possibly followed by `*', `+', or `?'. An atom
  73. %  followed by `*' matches a sequence of 0 or more matches of the atom. An
  74. %  atom followed by `+' matches a sequence of 1 or more matches of the
  75. %  atom. An atom followed by `?' matches a match of the atom, or the null
  76. %  pattern.
  77. %
  78. %  An atom is a regular expression in parentheses (matching a match for
  79. %  the regular expression), a range (see below), `.' (matching any single
  80. %  character), `^' (matching the null pattern at the beginning of the input
  81. %  pattern), `$' (matching the null pattern at the end of the input pattern),
  82. %  a `\' followed by a single character (matching that character), or a
  83. %  single character with no other significance (matching that character).
  84. %
  85. %  A range is a sequence of characters enclosed in `[]'. It normally
  86. %  matches any single character from the sequence. If the sequence begins
  87. %  with `^', it matches any single character not from the rest of the
  88. %  sequence. If two characters in the sequence are separated by `-', this
  89. %  is shorthand for the full list of ASCII characters between them (e.g.
  90. %  `[0-9]' matches any decimal digit). To include a literal `]' in the
  91. %  sequence, make it the first character (following a possible `^').  To
  92. %  include a literal `-', make it the first or last character.
  93. %
  94. %  If a regular expression could match two different parts of the input
  95. %  pattern, it will match the one which begins earliest. If both begin in
  96. %  the same place but match different lengths, or match the same length
  97. %  in different ways, life gets messier, as follows.
  98. %
  99. %  In general, the possibilities in a list of branches are considered in
  100. %  left-to-right order, the possibilities for `*', `+', and `?' are
  101. %  considered longest-first, nested constructs are considered from the
  102. %  outermost in, and concatenated constructs are considered
  103. %  leftmost-first. The match that will be chosen is the one that uses the
  104. %  earliest possibility in the first choice that has to be made. If there
  105. %  is more than one choice, the next will be made in the same manner
  106. %  (earliest possibility) subject to the decision on the first choice.
  107. %  And so forth.
  108. %
  109. %  For example, `(ab|a)b*c' could match `abc' in one of two ways. The
  110. %  first choice is between `ab' and `a'; since `ab' is earlier, and does
  111. %  lead to a successful overall match, it is chosen. Since the `b' is
  112. %  already spoken for, the `b*' must match its last possibility-the empty
  113. %  pattern-since it must respect the earlier choice.
  114. %
  115. %  In the particular case where no `|'s are present and there is only one
  116. %  `*', `+', or `?', the net effect is that the longest possible match
  117. %  will be chosen. So `ab*', presented with `xabbbby', will match `abbbb'.
  118. %  Note that if `ab*' is tried against `xabyabbbz', it will match `ab'
  119. %  just after `x', due to the begins-earliest rule. (In effect, the deci-
  120. %  sion on where to start the match is the first choice to be made, hence
  121. %  subsequent choices must respect it even if this leads them to
  122. %  less-preferred alternatives.)
  123. %
  124. %
  125. */
  126. X
  127. #include "xtp.h"
  128. #include "regular.h"
  129. X
  130. /*
  131. X  Variable declarations.
  132. */
  133. char
  134. X  *code,
  135. X  **subpattern_end,
  136. X  *p,
  137. X  start_code,
  138. X  *start_pattern,
  139. X  **subpattern;
  140. X
  141. static char
  142. X  *token;
  143. X
  144. static int
  145. X  number_parenthesis;
  146. X
  147. static long
  148. X  code_size;
  149. X
  150. /*
  151. X  Forward declarations.
  152. */
  153. static char
  154. X  *NextToken _Declare((register char *)),
  155. X  *Node _Declare((int)),
  156. X  *Piece _Declare((int *)),
  157. X  *Regular _Declare((int,int *));
  158. X
  159. static int
  160. X  Repeat _Declare((char *));
  161. X
  162. static void
  163. X  EmitCode _Declare((int)),
  164. X  Tail _Declare((char *,char *));
  165. X
  166. /*
  167. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  168. %                                                                             %
  169. %                                                                             %
  170. %                                                                             %
  171. %   A t o m                                                                   %
  172. %                                                                             %
  173. %                                                                             %
  174. %                                                                             %
  175. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  176. %
  177. %
  178. */
  179. static char *Atom(flagp)
  180. int
  181. X  *flagp;
  182. {
  183. X  int
  184. X    flags;
  185. X
  186. X  register char
  187. X    *status;
  188. X
  189. X  *flagp=WorstCase;
  190. X  switch(*token++)
  191. X  {
  192. X    case '^':
  193. X    {
  194. X      status=Node(MatchBeginningOfLine);
  195. X      break;
  196. X    }
  197. X    case '$':
  198. X    {
  199. X      status=Node(MatchEndOfProgramOfLine);
  200. X      break;
  201. X    }
  202. X    case '.':
  203. X    {
  204. X      status=Node(MatchAnyCharacter);
  205. X      *flagp|=NonNull | Simple;
  206. X      break;
  207. X    }
  208. X    case '[':
  209. X    {
  210. X      register int
  211. X        class,
  212. X        class_end;
  213. X
  214. X      if (*token != '^')
  215. X        status=Node(MatchAnyCharacterOf);
  216. X      else
  217. X        {
  218. X          /*
  219. X            Complement of range.
  220. X          */
  221. X          status=Node(MatchAnyCharacterBut);
  222. X          token++;
  223. X        }
  224. X      if ((*token == ']') || (*token == '-'))
  225. X        EmitCode(*token++);
  226. X      while ((*token != '\0') && (*token != ']'))
  227. X      {
  228. X        if (*token != '-')
  229. X          EmitCode(*token++);
  230. X         else
  231. X          {
  232. X            token++;
  233. X            if ((*token == ']') || (*token == '\0'))
  234. X              EmitCode('-');
  235. X            else
  236. X              {
  237. X                class=((int)*(unsigned char *)(token-2))+1;
  238. X                class_end=((int)*(unsigned char *)(token));
  239. X                if (class > class_end+1)
  240. X                  Fail("invalid [] range");
  241. X                for(; class <= class_end; class++)
  242. X                  EmitCode((char) class);
  243. X                token++;
  244. X              }
  245. X          }
  246. X      }
  247. X      EmitCode('\0');
  248. X      if (*token != ']')
  249. X        Fail("unmatched []");
  250. X      token++;
  251. X      *flagp|=NonNull | Simple;
  252. X      break;
  253. X    }
  254. X    case '(':
  255. X    {
  256. X      status=Regular(1,&flags);
  257. X      if (status == NULL)
  258. X        return(NULL);
  259. X      *flagp|=flags & (NonNull | SpecialStart);
  260. X      break;
  261. X    }
  262. X    case '\0':
  263. X    case '|':
  264. X    case ')':
  265. X    {
  266. X      Fail("internal urp");
  267. X      break;
  268. X    }
  269. X    case '?':
  270. X    case '+':
  271. X    case '*':
  272. X    {
  273. X      Fail("?+* follows nothing");
  274. X      break;
  275. X    }
  276. X    case '\\':
  277. X    {
  278. X      if (*token == '\0')
  279. X        Fail("trailing \\");
  280. X      status=Node(MatchExactly);
  281. X      EmitCode(*token++);
  282. X      EmitCode('\0');
  283. X      *flagp|=NonNull | Simple;
  284. X      break;
  285. X    }
  286. X    default:
  287. X    {
  288. X      register char
  289. X        ender;
  290. X
  291. X      register int
  292. X        length;
  293. X
  294. X      token--;
  295. X      length=strcspn(token,Meta);
  296. X      if (length <= 0)
  297. X        Fail("internal disaster");
  298. X      ender=(*(token+length));
  299. X      if (length > 1 && MultipleMatches(ender))
  300. X        length--;
  301. X      *flagp|=NonNull;
  302. X      if (length == 1)
  303. X        *flagp|=Simple;
  304. X      status=Node(MatchExactly);
  305. X      while (length > 0)
  306. X      {
  307. X        EmitCode(*token++);
  308. X        length--;
  309. X      }
  310. X      EmitCode('\0');
  311. X      break;
  312. X    }
  313. X  }
  314. X  return(status);
  315. }
  316. X
  317. /*
  318. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  319. %                                                                             %
  320. %                                                                             %
  321. %                                                                             %
  322. %   B r a n c h                                                               %
  323. %                                                                             %
  324. %                                                                             %
  325. %                                                                             %
  326. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  327. %
  328. %  Function Branch Implements the | operator.
  329. %
  330. %
  331. */
  332. static char *Branch(flagp)
  333. int
  334. X  *flagp;
  335. {
  336. X  int
  337. X    flags;
  338. X
  339. X  register char
  340. X    *chain,
  341. X    *latest,
  342. X    *status;
  343. X
  344. X  *flagp=WorstCase;
  345. X  status=Node(MatchThisOrNext);
  346. X  chain=NULL;
  347. X  while ((*token != '\0') && (*token != '|') && (*token != ')'))
  348. X  {
  349. X    latest=Piece(&flags);
  350. X    if (latest == NULL)
  351. X      return(NULL);
  352. X    *flagp|=flags & NonNull;
  353. X    if (chain == NULL)
  354. X      *flagp|=flags & SpecialStart;
  355. X    else
  356. X      Tail(chain,latest);
  357. X    chain=latest;
  358. X  }
  359. X  if (chain == NULL)
  360. X   (void) Node(MatchEmptyString);
  361. X  return(status);
  362. }
  363. X
  364. /*
  365. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  366. %                                                                             %
  367. %                                                                             %
  368. %                                                                             %
  369. %   E m i t C o d e                                                           %
  370. %                                                                             %
  371. %                                                                             %
  372. %                                                                             %
  373. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  374. %
  375. %
  376. */
  377. static void EmitCode(opcode)
  378. int
  379. X  opcode;
  380. {
  381. X  if (code != &start_code)
  382. X    *code++=(char) opcode;
  383. X  else
  384. X    code_size++;
  385. }
  386. X
  387. /*
  388. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  389. %                                                                             %
  390. %                                                                             %
  391. %                                                                             %
  392. %   I n s e r t                                                               %
  393. %                                                                             %
  394. %                                                                             %
  395. %                                                                             %
  396. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  397. %
  398. %  Function Insert inserts an operator in front of an already-emitted operand.
  399. %
  400. */
  401. static void Insert(opcode,operand)
  402. char
  403. X  opcode,
  404. X  *operand;
  405. {
  406. X  register char
  407. X    *p,
  408. X    *place,
  409. X    *q;
  410. X
  411. X  if (code == &start_code)
  412. X    {
  413. X      code_size+=3;
  414. X      return;
  415. X    }
  416. X  p=code;
  417. X  code+=3;
  418. X  q=code;
  419. X  while (p > operand)
  420. X    *--q=(*--p);
  421. X  place=operand;
  422. X  *place++=opcode;
  423. X  *place++='\0';
  424. X  *place++='\0';
  425. }
  426. X
  427. /*
  428. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  429. %                                                                             %
  430. %                                                                             %
  431. %                                                                             %
  432. %   M a t c h                                                                 %
  433. %                                                                             %
  434. %                                                                             %
  435. %                                                                             %
  436. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  437. %
  438. %
  439. */
  440. static int Match(regular_expression)
  441. char
  442. X  *regular_expression;
  443. {
  444. X  char
  445. X    *next_token;
  446. X
  447. X  register char
  448. X    *scan;
  449. X
  450. X  scan=regular_expression;
  451. X  while (scan != NULL)
  452. X  {
  453. X    next_token=NextToken(scan);
  454. X    switch(OpCode(scan))
  455. X    {
  456. X      case MatchBeginningOfLine:
  457. X      {
  458. X        if (p != start_pattern)
  459. X          return(0);
  460. X        break;
  461. X      }
  462. X      case MatchEndOfProgramOfLine:
  463. X      {
  464. X        if (*p != '\0')
  465. X         return(0);
  466. X        break;
  467. X      }
  468. X      case MatchAnyCharacter:
  469. X      {
  470. X        if (*p == '\0')
  471. X          return(0);
  472. X        p++;
  473. X        break;
  474. X      }
  475. X      case MatchExactly:
  476. X      {
  477. X        register char
  478. X          *operand;
  479. X
  480. X        register int
  481. X          length;
  482. X
  483. X        operand=Operand(scan);
  484. X        /*
  485. X          Inline the first character for speed.
  486. X        */
  487. X        if (*operand != *p)
  488. X          return(0);
  489. X        length=strlen(operand);
  490. X        if ((length > 1) && (strncmp(operand,p,length) != 0))
  491. X          return(0);
  492. X        p+=length;
  493. X        break;
  494. X      }
  495. X      case MatchAnyCharacterOf:
  496. X      {
  497. X        if ((*p == '\0' || strchr(Operand(scan),*p) == NULL))
  498. X          return(0);
  499. X        p++;
  500. X        break;
  501. X      }
  502. X      case MatchAnyCharacterBut:
  503. X      {
  504. X        if ((*p == '\0') || (strchr(Operand(scan),*p) != NULL))
  505. X          return(0);
  506. X        p++;
  507. X        break;
  508. X      }
  509. X      case MatchEmptyString:
  510. X        break;
  511. X      case Back:
  512. X        break;
  513. X      case Open+1:
  514. X      case Open+2:
  515. X      case Open+3:
  516. X      case Open+4:
  517. X      case Open+5:
  518. X      case Open+6:
  519. X      case Open+7:
  520. X      case Open+8:
  521. X      case Open+9:
  522. X      {
  523. X        register char
  524. X          *save;
  525. X
  526. X        register int
  527. X          no;
  528. X
  529. X        no=OpCode(scan)-Open;
  530. X        save=p;
  531. X        if (!Match(next_token))
  532. X          return(0);
  533. X        else
  534. X          {
  535. X            /*
  536. X              Don't set subpattern if some later invocation of the same
  537. X              parentheses already has.
  538. X            */
  539. X            if (subpattern[no] == NULL)
  540. X              subpattern[no]=save;
  541. X            return(1);
  542. X          }
  543. X        break;
  544. X      }
  545. X      case Close+1:
  546. X      case Close+2:
  547. X      case Close+3:
  548. X      case Close+4:
  549. X      case Close+5:
  550. X      case Close+6:
  551. X      case Close+7:
  552. X      case Close+8:
  553. X      case Close+9:
  554. X      {
  555. X        register char
  556. X          *save;
  557. X
  558. X        register int
  559. X          no;
  560. X
  561. X        no=OpCode(scan)-Close;
  562. X        save=p;
  563. X        if (!Match(next_token))
  564. X           return(0);
  565. X        else
  566. X          {
  567. X            /*
  568. X              Don't set subpattern_end if some later invocation of the same
  569. X              parentheses already has.
  570. X            */
  571. X            if (subpattern_end[no] == NULL)
  572. X              subpattern_end[no]=save;
  573. X            return(1);
  574. X          }
  575. X        break;
  576. X      }
  577. X      case MatchThisOrNext:
  578. X      {
  579. X        register char
  580. X          *save;
  581. X
  582. X        if (OpCode(next_token) != MatchThisOrNext)
  583. X          next_token=Operand(scan);
  584. X        else
  585. X          {
  586. X            do
  587. X            {
  588. X              save=p;
  589. X              if (Match(Operand(scan)))
  590. X                return(1);
  591. X              p=save;
  592. X              scan=NextToken(scan);
  593. X            } while ((scan != NULL) && (OpCode(scan) == MatchThisOrNext));
  594. X            return(0);
  595. X          }
  596. X        break;
  597. X      }
  598. X      case MatchZeroOrMore:
  599. X      case MatchOneOrMore:
  600. X      {
  601. X        register char
  602. X          next_tokench,
  603. X          *save;
  604. X
  605. X        register int
  606. X          min,
  607. X          no;
  608. X
  609. X        /*
  610. X          Lookahead to avoid useless match attempts when we know what
  611. X          character comes next_token.
  612. X        */
  613. X        next_tokench='\0';
  614. X        if (OpCode(next_token) == MatchExactly)
  615. X          next_tokench=(*Operand(next_token));
  616. X        min=(OpCode(scan) == MatchZeroOrMore) ? 0 : 1;
  617. X        save=p;
  618. X        no=Repeat(Operand(scan));
  619. X        while (no >= min)
  620. X        {
  621. X          /*
  622. X            If it could work, try it.
  623. X          */
  624. X          if ((next_tokench == '\0') || (*p == next_tokench))
  625. X            if (Match(next_token))
  626. X              return(1);
  627. X          /*
  628. X            Couldn't or didn't -- back up.
  629. X          */
  630. X          no--;
  631. X          p=save+no;
  632. X        }
  633. X        return(0);
  634. X        break;
  635. X      }
  636. X      case EndOfProgram:
  637. X        return(1);
  638. X        break;
  639. X      default:
  640. X        (void) fprintf(stderr,"Regular(3): %s","memory corruption");
  641. X        return(0);
  642. X        break;
  643. X    }
  644. X    scan=next_token;
  645. X  }
  646. X  (void) fprintf(stderr,"Regular(3): %s","corrupted pointers");
  647. X  return(0);
  648. }
  649. X
  650. /*
  651. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  652. %                                                                             %
  653. %                                                                             %
  654. %                                                                             %
  655. %   N e x t T o k e n                                                         %
  656. %                                                                             %
  657. %                                                                             %
  658. %                                                                             %
  659. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  660. %
  661. %
  662. */
  663. static char *NextToken(p)
  664. register char
  665. X  *p;
  666. {
  667. X  register int
  668. X    offset;
  669. X
  670. X  if (p == &start_code)
  671. X    return(NULL);
  672. X  offset=Next(p);
  673. X  if (offset == 0)
  674. X    return(NULL);
  675. X  if (OpCode(p) == Back)
  676. X    return(p-offset);
  677. X  else
  678. X    return(p+offset);
  679. }
  680. X
  681. /*
  682. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  683. %                                                                             %
  684. %                                                                             %
  685. %                                                                             %
  686. %   N o d e                                                                   %
  687. %                                                                             %
  688. %                                                                             %
  689. %                                                                             %
  690. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  691. %
  692. %
  693. */
  694. static char *Node(opcode)
  695. int
  696. X  opcode;
  697. {
  698. X  register char
  699. X    *ptr,
  700. X    *status;
  701. X
  702. X  status=code;
  703. X  if (status == &start_code)
  704. X    {
  705. X      code_size+=3;
  706. X      return(status);
  707. X    }
  708. X  ptr=status;
  709. X  *ptr++=(char) opcode;
  710. X  *ptr++='\0';
  711. X  *ptr++='\0';
  712. X  code=ptr;
  713. X  return(status);
  714. }
  715. X
  716. /*
  717. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  718. %                                                                             %
  719. %                                                                             %
  720. %                                                                             %
  721. %   O p T a i l                                                               %
  722. %                                                                             %
  723. %                                                                             %
  724. %                                                                             %
  725. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  726. %
  727. %
  728. */
  729. static void OpTail(p,value)
  730. char
  731. X  *p;
  732. X
  733. char
  734. X  *value;
  735. {
  736. X  /*
  737. X    "Operandless" and "op != MatchThisOrNext" are synonymous in practice.
  738. X  */
  739. X  if ((p == NULL) || (p == &start_code) || (OpCode(p) != MatchThisOrNext))
  740. X    return;
  741. X  Tail(Operand(p),value);
  742. }
  743. X
  744. /*
  745. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  746. %                                                                             %
  747. %                                                                             %
  748. %                                                                             %
  749. %   P i e c e                                                                 %
  750. %                                                                             %
  751. %                                                                             %
  752. %                                                                             %
  753. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  754. %
  755. %
  756. */
  757. static char *Piece(flagp)
  758. int
  759. X  *flagp;
  760. {
  761. X  int
  762. X    flags;
  763. X
  764. X  register char
  765. X    *next_token,
  766. X    op,
  767. X    *status;
  768. X
  769. X  status=Atom(&flags);
  770. X  if (status == NULL)
  771. X    return(NULL);
  772. X  op=(*token);
  773. X  if (!MultipleMatches(op))
  774. X    {
  775. X      *flagp=flags;
  776. X      return(status);
  777. X    }
  778. X  if (!(flags & NonNull) && op != '?')
  779. X    Fail("*+ operand could be empty");
  780. X  *flagp=(op != '+') ? (WorstCase | SpecialStart) : (WorstCase | NonNull);
  781. X  if (op == '*' && (flags & Simple))
  782. X    Insert(MatchZeroOrMore,status);
  783. X  else
  784. X    if (op == '*')
  785. X      {
  786. X        /*
  787. X          Emit x* as (x&|), where & means "self".
  788. X        */
  789. X        Insert(MatchThisOrNext,status);
  790. X        OpTail(status,Node(Back));
  791. X        OpTail(status,status);
  792. X        Tail(status,Node(MatchThisOrNext));
  793. X        Tail(status,Node(MatchEmptyString));
  794. X      }
  795. X    else
  796. X      if ((op == '+') && (flags & Simple))
  797. X        Insert(MatchOneOrMore,status);
  798. X      else
  799. X        if (op == '+')
  800. X          {
  801. X            /*
  802. X              Emit x+ as x (&|), where & means "self".
  803. X            */
  804. X            next_token=Node(MatchThisOrNext);
  805. X            Tail(status,next_token);
  806. X            Tail(Node(Back),status);
  807. X            Tail(next_token,Node(MatchThisOrNext));
  808. X            Tail(status,Node(MatchEmptyString));
  809. X          }
  810. X        else
  811. X          if (op == '?')
  812. X            {
  813. X              /*
  814. X                Emit x? as (x|)
  815. X              */
  816. X              Insert(MatchThisOrNext,status);
  817. X              Tail(status,Node(MatchThisOrNext));
  818. X              next_token=Node(MatchEmptyString);
  819. X              Tail(status,next_token);
  820. X              OpTail(status,next_token);
  821. X            }
  822. X  token++;
  823. X  if (MultipleMatches(*token))
  824. X    Fail("nested *?+");
  825. X  return(status);
  826. }
  827. X
  828. /*
  829. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  830. %                                                                             %
  831. %                                                                             %
  832. %                                                                             %
  833. %   R e g u l a r                                                             %
  834. %                                                                             %
  835. %                                                                             %
  836. %                                                                             %
  837. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  838. %
  839. %
  840. */
  841. static char *Regular(parenthesized,flagp)
  842. int
  843. X  parenthesized;
  844. X
  845. int
  846. X  *flagp;
  847. {
  848. X  int
  849. X    flags;
  850. X
  851. X  register char
  852. X    *br,
  853. X    *ender,
  854. X    *status;
  855. X
  856. X  register int
  857. X    count;
  858. X
  859. X  count=0;
  860. X  *flagp=NonNull;
  861. X  if (!parenthesized)
  862. X    status=NULL;
  863. X  else
  864. X    {
  865. X      /*
  866. X        Make an Open node.
  867. X      */
  868. X      if (number_parenthesis >= NumberSubExpressions)
  869. X        Fail("too many ()");
  870. X      count=number_parenthesis;
  871. X      number_parenthesis++;
  872. X      status=Node(Open+count);
  873. X    }
  874. X  /*
  875. X    Pick up the branches, linking them together.
  876. X  */
  877. X  br=Branch(&flags);
  878. X  if (br == NULL)
  879. X    return(NULL);
  880. X  if (status != NULL)
  881. X    Tail(status,br);
  882. X  else
  883. X    status=br;
  884. X  if (!(flags & NonNull))
  885. X    *flagp&=(~NonNull);
  886. X  *flagp|=flags & SpecialStart;
  887. X  while (*token == '|')
  888. X  {
  889. X    token++;
  890. X    br=Branch(&flags);
  891. X    if (br == NULL)
  892. X      return(NULL);
  893. X    Tail(status,br);
  894. X    if (!(flags & NonNull))
  895. X      *flagp &= ~NonNull;
  896. X    *flagp|=flags & SpecialStart;
  897. X  }
  898. X  /*
  899. X    Make a closing node and hook it on the end.
  900. X  */
  901. X  ender=Node((parenthesized) ? Close+count : EndOfProgram);
  902. X  Tail(status,ender);
  903. X  /*
  904. X    Hook the tails of the branches to the closing node.
  905. X  */
  906. X  for(br=status; br != NULL; br=NextToken(br))
  907. X    OpTail(br,ender);
  908. X  /*
  909. X    Check for proper termination.
  910. X  */
  911. X  if (parenthesized && (*token++ != ')'))
  912. X    Fail("unmatched()")
  913. X  else
  914. X    if (!parenthesized && (*token != '\0'))
  915. X      {
  916. X        if (*token == ')')
  917. X          Fail("unmatched()")
  918. X        else
  919. X          Fail("junk on end")
  920. X       }
  921. X  return(status);
  922. }
  923. X
  924. /*
  925. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  926. %                                                                             %
  927. %                                                                             %
  928. %                                                                             %
  929. %   R e p e a t                                                               %
  930. %                                                                             %
  931. %                                                                             %
  932. %                                                                             %
  933. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  934. %
  935. %
  936. */
  937. static int Repeat(p)
  938. char
  939. X  *p;
  940. {
  941. X  register char
  942. X    *operand,
  943. X    *scan;
  944. X
  945. X  register int
  946. X    count=0;
  947. X
  948. X  scan=p;
  949. X  operand=Operand(p);
  950. X  switch(OpCode(p))
  951. X  {
  952. X    case MatchAnyCharacter:
  953. X    {
  954. X      count=strlen(scan);
  955. X      scan+=count;
  956. X      break;
  957. X    }
  958. X    case MatchExactly:
  959. X    {
  960. X      while (*operand == *scan)
  961. X      {
  962. X        count++;
  963. X        scan++;
  964. X      }
  965. X      break;
  966. X    }
  967. X    case MatchAnyCharacterOf:
  968. X    {
  969. X      while ((*scan != '\0') && (strchr(operand,*scan) != NULL))
  970. X      {
  971. X        count++;
  972. X        scan++;
  973. X      }
  974. X      break;
  975. X    }
  976. X    case MatchAnyCharacterBut:
  977. X    {
  978. X      while ((*scan != '\0') && (strchr(operand,*scan) == NULL))
  979. X      {
  980. X        count++;
  981. X        scan++;
  982. X      }
  983. X      break;
  984. X    }
  985. X    default:
  986. X    {
  987. X      (void) fprintf(stderr,"Regular(3): %s","internal foulup");
  988. X      count=0;
  989. X      break;
  990. X    }
  991. X  }
  992. X  p=scan;
  993. X  return(count);
  994. }
  995. X
  996. /*
  997. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  998. %                                                                             %
  999. %                                                                             %
  1000. %                                                                             %
  1001. %   T a i l                                                                   %
  1002. %                                                                             %
  1003. %                                                                             %
  1004. %                                                                             %
  1005. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1006. %
  1007. %
  1008. */
  1009. static void Tail(p,val)
  1010. char
  1011. X  *p;
  1012. X
  1013. char
  1014. X  *val;
  1015. {
  1016. X  register char
  1017. X    *scan,
  1018. X    *temp;
  1019. X
  1020. X  register int
  1021. X    offset;
  1022. X
  1023. X  if (p == &start_code)
  1024. X    return;
  1025. X  /*
  1026. X    Find last node.
  1027. X  */
  1028. X  scan=p;
  1029. X  for(;;)
  1030. X  {
  1031. X    temp=NextToken(scan);
  1032. X    if (temp == NULL)
  1033. X      break;
  1034. X    scan=temp;
  1035. X  }
  1036. X  if (OpCode(scan) == Back)
  1037. X    offset=scan-val;
  1038. X  else
  1039. X    offset=val-scan;
  1040. X  *(scan+1)=(offset >> 8) & 0377;
  1041. X  *(scan+2)=offset & 0377;
  1042. }
  1043. X
  1044. /*
  1045. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1046. %                                                                             %
  1047. %                                                                             %
  1048. %                                                                             %
  1049. %   T r y                                                                     %
  1050. %                                                                             %
  1051. %                                                                             %
  1052. %                                                                             %
  1053. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1054. %
  1055. %
  1056. */
  1057. static int Try(regular_expression,pattern)
  1058. RegularExpression
  1059. X  *regular_expression;
  1060. X
  1061. char
  1062. X  *pattern;
  1063. {
  1064. X  register char
  1065. X    **ep,
  1066. X    **sp;
  1067. X
  1068. X  register int
  1069. X    i;
  1070. X
  1071. X  p=pattern;
  1072. X  subpattern=regular_expression->subpattern;
  1073. X  subpattern_end=regular_expression->subpattern_end;
  1074. X  sp=regular_expression->subpattern;
  1075. X  ep=regular_expression->subpattern_end;
  1076. X  for(i=NumberSubExpressions; i > 0; i--)
  1077. X  {
  1078. X    *sp++=NULL;
  1079. X    *ep++=NULL;
  1080. X  }
  1081. X  if (!Match(regular_expression->program+1))
  1082. X    return(0);
  1083. X  else
  1084. X    {
  1085. X      regular_expression->subpattern[0]=pattern;
  1086. X      regular_expression->subpattern_end[0]=p;
  1087. X      return(1);
  1088. X    }
  1089. }
  1090. X
  1091. /*
  1092. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1093. %                                                                             %
  1094. %                                                                             %
  1095. %                                                                             %
  1096. %   C o m p i l e R e g u l a r E x p r e s s i o n                           %
  1097. %                                                                             %
  1098. %                                                                             %
  1099. %                                                                             %
  1100. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1101. %
  1102. %  Function CompileRegularExpression compiles a regular expression into a
  1103. %  structure of type RegularExpression and returns a pointer to it.  The space
  1104. %  is allocated using function malloc and may be released by function free.
  1105. %
  1106. %
  1107. */
  1108. RegularExpression *CompileRegularExpression(regular_expression)
  1109. char
  1110. X  *regular_expression;
  1111. {
  1112. X  int
  1113. X    flags;
  1114. X
  1115. X  register char
  1116. X    *longest,
  1117. X    *scan;
  1118. X
  1119. X  register RegularExpression
  1120. X    *r;
  1121. X
  1122. X  register int
  1123. X    length;
  1124. X
  1125. X  if (regular_expression == NULL)
  1126. X    Fail("NULL argument");
  1127. X  /*
  1128. X    First pass: determine size.
  1129. X  */
  1130. X  token=regular_expression;
  1131. X  number_parenthesis=1;
  1132. X  code_size=0L;
  1133. X  code=(&start_code);
  1134. X  EmitCode(Magick);
  1135. X  if (Regular(0,&flags) == NULL)
  1136. X    return(NULL);
  1137. X  /*
  1138. X    Allocate space.
  1139. X  */
  1140. X  r=(RegularExpression *) malloc((code_size+sizeof(RegularExpression)));
  1141. X  if (r == (RegularExpression *) NULL)
  1142. X    Fail("out of space");
  1143. X  /*
  1144. X    Second pass: emit code.
  1145. X  */
  1146. X  token=regular_expression;
  1147. X  number_parenthesis=1;
  1148. X  code=r->program;
  1149. X  EmitCode(Magick);
  1150. X  if (Regular(0,&flags) == NULL)
  1151. X    return(NULL);
  1152. X  /*
  1153. X    Dig out information for optimizations.
  1154. X  */
  1155. X  r->start_character='\0';
  1156. X  r->anchor=0;
  1157. X  r->priority_pattern=NULL;
  1158. X  r->pattern_length=0;
  1159. X  scan=r->program+1;
  1160. X  if (OpCode(NextToken(scan)) == EndOfProgram)
  1161. X    {
  1162. X      scan=Operand(scan);
  1163. X      if (OpCode(scan) == MatchExactly)
  1164. X        r->start_character=(*Operand(scan));
  1165. X      else
  1166. X        if (OpCode(scan) == MatchBeginningOfLine)
  1167. X          r->anchor++;
  1168. X      /*
  1169. X        If there's something expensive in the regular expression, find the
  1170. X        longest literal pattern that must appear and make it the
  1171. X        priority_pattern.
  1172. X      */
  1173. X      if (flags & SpecialStart)
  1174. X        {
  1175. X          longest=NULL;
  1176. X          length=0;
  1177. X          for(; scan != NULL; scan=NextToken(scan))
  1178. X            if ((OpCode(scan) == MatchExactly) &&
  1179. X                (strlen(Operand(scan)) >= length))
  1180. X              {
  1181. X                longest=Operand(scan);
  1182. X                length=strlen(Operand(scan));
  1183. X              }
  1184. X          r->priority_pattern=longest;
  1185. X          r->pattern_length=length;
  1186. X        }
  1187. X    }
  1188. X  return(r);
  1189. }
  1190. X
  1191. /*
  1192. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1193. %                                                                             %
  1194. %                                                                             %
  1195. %                                                                             %
  1196. %   E x e c u t e R e g u l a r E x p r e s s i o n                           %
  1197. %                                                                             %
  1198. %                                                                             %
  1199. %                                                                             %
  1200. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1201. %
  1202. %  Function ExecuteRegularExpression matches a NULL-terminated pattern against
  1203. %  the compiled regular expression in regular-expression.  It returns 1 for
  1204. %  success and 0 for failure.
  1205. %
  1206. %
  1207. */
  1208. int ExecuteRegularExpression(regular_expression,pattern)
  1209. register RegularExpression
  1210. X  *regular_expression;
  1211. X
  1212. register char
  1213. X  *pattern;
  1214. {
  1215. X  register char
  1216. X    *s;
  1217. X
  1218. X  if ((regular_expression == (RegularExpression *) NULL) ||
  1219. X      (pattern == (char *) NULL))
  1220. X    {
  1221. X      (void) fprintf(stderr,"Regular(3): %s","NULL parameter\n");
  1222. X      return(0);
  1223. X    }
  1224. X  /*
  1225. X    Check validity of program.
  1226. X  */
  1227. X  if (((int)*(unsigned char *)(regular_expression->program)) != Magick)
  1228. X    {
  1229. X      (void) fprintf(stderr,"Regular(3): %s","corrupted program");
  1230. X      return(0);
  1231. X    }
  1232. X  /*
  1233. X    If there is a "must appear" pattern, look for it.
  1234. X  */
  1235. X  if (regular_expression->priority_pattern != NULL)
  1236. X    {
  1237. X      s=pattern;
  1238. X      while ((s=strchr(s,regular_expression->priority_pattern[0])) != NULL)
  1239. X      {
  1240. X        if (strncmp(s,regular_expression->priority_pattern,
  1241. X            regular_expression->pattern_length) == 0)
  1242. X          break;
  1243. X        s++;
  1244. X       }
  1245. X       if (s == NULL)
  1246. X         return(0);
  1247. X    }
  1248. X  /*
  1249. X    Mark beginning of line for ^.
  1250. X  */
  1251. X  start_pattern=pattern;
  1252. X  /*
  1253. X    Simplest case:  anchored match need be tried only once.
  1254. X  */
  1255. X  if (regular_expression->anchor)
  1256. X    return(Try(regular_expression,pattern));
  1257. X  /*
  1258. X    Messy cases:  unanchored match.
  1259. X  */
  1260. X  s=pattern;
  1261. X  if (regular_expression->start_character != '\0')
  1262. X    while ((s=strchr(s,regular_expression->start_character)) != NULL)
  1263. X    {
  1264. X      if (Try(regular_expression,s))
  1265. X        return(1);
  1266. X      s++;
  1267. X    }
  1268. X  else
  1269. X    do
  1270. X    {
  1271. X      if (Try(regular_expression,s))
  1272. X        return(1);
  1273. X    } while (*s++ != '\0');
  1274. X  return(0);
  1275. }
  1276. SHAR_EOF
  1277. echo 'File ImageMagick/xtp/regular.c is complete' &&
  1278. chmod 0644 ImageMagick/xtp/regular.c ||
  1279. echo 'restore of ImageMagick/xtp/regular.c failed'
  1280. Wc_c="`wc -c < 'ImageMagick/xtp/regular.c'`"
  1281. test 36656 -eq "$Wc_c" ||
  1282.     echo 'ImageMagick/xtp/regular.c: original size 36656, current size' "$Wc_c"
  1283. rm -f _shar_wnt_.tmp
  1284. fi
  1285. # ============= ImageMagick/xtp/regular.h ==============
  1286. if test -f 'ImageMagick/xtp/regular.h' -a X"$1" != X"-c"; then
  1287.     echo 'x - skipping ImageMagick/xtp/regular.h (File already exists)'
  1288.     rm -f _shar_wnt_.tmp
  1289. else
  1290. > _shar_wnt_.tmp
  1291. echo 'x - extracting ImageMagick/xtp/regular.h (Text)'
  1292. sed 's/^X//' << 'SHAR_EOF' > 'ImageMagick/xtp/regular.h' &&
  1293. /*
  1294. X  Definitions etc. for RegularExpression(3) routines.
  1295. */
  1296. #define EndOfProgram  0
  1297. #define MatchBeginningOfLine  1
  1298. #define MatchEndOfProgramOfLine  2
  1299. #define MatchAnyCharacter  3
  1300. #define MatchAnyCharacterOf  4
  1301. #define MatchAnyCharacterBut  5
  1302. #define MatchThisOrNext  6
  1303. #define Back  7
  1304. #define MatchExactly  8
  1305. #define MatchEmptyString  9
  1306. #define MatchZeroOrMore  10
  1307. #define MatchOneOrMore  11
  1308. #define Open  20
  1309. #define Close  30
  1310. X
  1311. #define WorstCase  0
  1312. #define NonNull  1
  1313. #define Simple  2
  1314. #define SpecialStart  4
  1315. X
  1316. #define Fail(m)  \
  1317. {  \
  1318. X  (void) fprintf(stderr,"RegularExpression: %s\n",m);  \
  1319. X  return(NULL);  \
  1320. }
  1321. #define Magick   0234
  1322. #define Meta  "^$.[()|?+*\\"
  1323. #define MultipleMatches(c) (((c) == '*') || ((c) == '+') || ((c) == '?'))
  1324. #define Next(p) (((*((p)+1) & 0377) << 8 )+(*((p)+2) & 0377))
  1325. #define NumberSubExpressions  10
  1326. #define OpCode(p) (*(p))
  1327. #define Operand(p) ((p)+3)
  1328. X
  1329. typedef struct _RegularExpression 
  1330. {
  1331. X  char 
  1332. X    *subpattern[NumberSubExpressions],
  1333. X    *subpattern_end[NumberSubExpressions],
  1334. X    start_character,
  1335. X    anchor,
  1336. X    *priority_pattern;
  1337. X
  1338. X  int 
  1339. X    pattern_length;
  1340. X
  1341. X  char 
  1342. X    program[1];
  1343. } RegularExpression;
  1344. X
  1345. extern RegularExpression 
  1346. X  *CompileRegularExpression _Declare((char *));
  1347. X
  1348. extern int 
  1349. X  ExecuteRegularExpression _Declare((RegularExpression *,char *));
  1350. SHAR_EOF
  1351. chmod 0644 ImageMagick/xtp/regular.h ||
  1352. echo 'restore of ImageMagick/xtp/regular.h failed'
  1353. Wc_c="`wc -c < 'ImageMagick/xtp/regular.h'`"
  1354. test 1299 -eq "$Wc_c" ||
  1355.     echo 'ImageMagick/xtp/regular.h: original size 1299, current size' "$Wc_c"
  1356. rm -f _shar_wnt_.tmp
  1357. fi
  1358. # ============= ImageMagick/xtp/xtp.c ==============
  1359. if test -f 'ImageMagick/xtp/xtp.c' -a X"$1" != X"-c"; then
  1360.     echo 'x - skipping ImageMagick/xtp/xtp.c (File already exists)'
  1361.     rm -f _shar_wnt_.tmp
  1362. else
  1363. > _shar_wnt_.tmp
  1364. echo 'x - extracting ImageMagick/xtp/xtp.c (Text)'
  1365. sed 's/^X//' << 'SHAR_EOF' > 'ImageMagick/xtp/xtp.c' &&
  1366. /*
  1367. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1368. %                                                                             %
  1369. %                                                                             %
  1370. %                                                                             %
  1371. %                            X   X  TTTTT PPPP                                %
  1372. %                             X X     T   P   P                               %
  1373. %                              X      T   PPPP                                %
  1374. %                             X X     T   P                                   %
  1375. %                            X   X    T   P                                   %
  1376. %                                                                             %
  1377. %                                                                             %
  1378. %                         File transfer program.                              %
  1379. %                                                                             %
  1380. %                                                                             %
  1381. %                                                                             %
  1382. %                           Software Design                                   %
  1383. %                             John Cristy                                     %
  1384. %                             October 1992                                    %
  1385. %                                                                             %
  1386. %                                                                             %
  1387. %  Copyright 1992 E. I. Dupont de Nemours & Company                           %
  1388. %                                                                             %
  1389. %  Permission to use, copy, modify, distribute, and sell this software and    %
  1390. %  its documentation for any purpose is hereby granted without fee,           %
  1391. %  provided that the above copyright notice appear in all copies and that     %
  1392. %  both that copyright notice and this permission notice appear in            %
  1393. %  supporting documentation, and that the name of E. I. Dupont de Nemours     %
  1394. %  & Company not be used in advertising or publicity pertaining to            %
  1395. %  distribution of the software without specific, written prior               %
  1396. %  permission.  E. I. Dupont de Nemours & Company makes no representations    %
  1397. %  about the suitability of this software for any purpose.  It is provided    %
  1398. %  "as is" without express or implied warranty.                               %
  1399. %                                                                             %
  1400. %  E. I. Dupont de Nemours & Company disclaims all warranties with regard     %
  1401. %  to this software, including all implied warranties of merchantability      %
  1402. %  and fitness, in no event shall E. I. Dupont de Nemours & Company be        %
  1403. %  liable for any special, indirect or consequential damages or any           %
  1404. %  damages whatsoever resulting from loss of use, data or profits, whether    %
  1405. %  in an action of contract, negligence or other tortious action, arising     %
  1406. %  out of or in connection with the use or performance of this software.      %
  1407. %                                                                             %
  1408. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1409. %
  1410. %  Xtp is a utility for retrieving, listing, or printing files from a
  1411. %  remote network site.  Xtp performs most of the same functions as the
  1412. %  FTP program, but does not require any interactive commands.  You simply
  1413. %  specify the file transfer task on the command line and xtp performs the
  1414. %  transfer automatically.
  1415. %
  1416. %  This program was adapted from a similiar program written by Steve Singles,
  1417. %  University of Delaware.
  1418. %
  1419. %  Command syntax:
  1420. %
  1421. %  Usage: xtp [-options ...] <host/ip address> [ <home directory> ]
  1422. %
  1423. %  Where options include:
  1424. %    -binary                retrieve files as binary
  1425. %    -exclude expression    exclude files that match the expression
  1426. %    -directory expression  list file names that match the expression
  1427. %    -ident password        specifies password
  1428. %    -port number           port number of FTP server
  1429. %    -print expression      print files that match the expression
  1430. %    -prune                 do not recursively search for files
  1431. %    -retrieve expression   retrieve files that match the expression
  1432. %    -send expression       send files that match the expression
  1433. %    -timeout seconds       specifies maximum seconds of XTP session
  1434. %    -user name             identify yourself to the remote FTP server
  1435. %
  1436. %
  1437. */
  1438. X
  1439. /*
  1440. X  Include declarations.
  1441. */
  1442. #define _POSIX_SOURCE  1
  1443. #include "xtp.h"
  1444. #include "regular.h"
  1445. #include <unistd.h>
  1446. #include <sys/types.h>
  1447. #include <signal.h>
  1448. #include <termios.h>
  1449. #include <fcntl.h>
  1450. #include <sys/stat.h>
  1451. #include <sys/wait.h>
  1452. /*
  1453. X  Variable declarations.
  1454. */
  1455. static char
  1456. X  *application_name,
  1457. X  slave_tty[16];
  1458. X
  1459. static int
  1460. X  master,
  1461. X  status;
  1462. X
  1463. static RegularExpression
  1464. X  *directory_expression,
  1465. X  *exclude_expression,
  1466. X  *print_expression,
  1467. X  *retrieve_expression;
  1468. X
  1469. /*
  1470. X  External declarations.
  1471. */
  1472. extern char
  1473. X  *GetHostInfo _Declare((char *));
  1474. X
  1475. /*
  1476. X  Forward declarations.
  1477. */
  1478. static char
  1479. X  *Wait _Declare((void));
  1480. X
  1481. static void
  1482. X  DirectoryRequest _Declare((char *, char *)),
  1483. X  PrintRequest _Declare((char *,unsigned int)),
  1484. X  RetrieveRequest _Declare((char *,unsigned int));
  1485. X
  1486. /*
  1487. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1488. %                                                                             %
  1489. %                                                                             %
  1490. %                                                                             %
  1491. %   D i r e c t o r y R e q u e s t                                           %
  1492. %                                                                             %
  1493. %                                                                             %
  1494. %                                                                             %
  1495. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1496. %
  1497. %  Function DirectoryRequest lists a file name and its attributes.
  1498. %
  1499. %  The format of the DirectoryRequest routine is:
  1500. %
  1501. %    DirectoryRequest(fileinfo,filename)
  1502. %
  1503. %  A description of each parameter follows:
  1504. %
  1505. %    o filename:  Specifies a pointer to a character array that contains
  1506. %      information about the file.
  1507. %
  1508. %    o filename:  Specifies a pointer to a character array that contains
  1509. %      the name of the file.
  1510. %
  1511. */
  1512. static void DirectoryRequest(fileinfo,filename)
  1513. char
  1514. X  *fileinfo,
  1515. X  *filename;
  1516. {
  1517. X  status=0;
  1518. X  if (*fileinfo == '\0')
  1519. X    (void) fprintf(stdout,"%s\n",filename);
  1520. X  else
  1521. X    (void) fprintf(stdout,"%s %s\n",fileinfo,filename);
  1522. }
  1523. X
  1524. /*
  1525. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1526. %                                                                             %
  1527. %                                                                             %
  1528. %                                                                             %
  1529. %   E r r o r                                                                 %
  1530. %                                                                             %
  1531. %                                                                             %
  1532. %                                                                             %
  1533. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1534. %
  1535. %  Function Error displays an error message and then terminates the program.
  1536. %
  1537. %  The format of the Error routine is:
  1538. %
  1539. %      Error(message,qualifier)
  1540. %
  1541. %  A description of each parameter follows:
  1542. %
  1543. %    o message: Specifies the message to display before terminating the
  1544. %      program.
  1545. %
  1546. %    o qualifier: Specifies any qualifier to the message.
  1547. %
  1548. %
  1549. */
  1550. void Error(message,qualifier)
  1551. char
  1552. X  *message,
  1553. X  *qualifier;
  1554. {
  1555. X  (void) fprintf(stderr,"%s: %s",application_name,message);
  1556. X  if (qualifier != (char *) NULL)
  1557. X    (void) fprintf(stderr," (%s)",qualifier);
  1558. X  (void) fprintf(stderr,".\n");
  1559. X  exit(1);
  1560. }
  1561. X
  1562. /*
  1563. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1564. %                                                                             %
  1565. %                                                                             %
  1566. %                                                                             %
  1567. %   E x e c u t e F t p                                                       %
  1568. %                                                                             %
  1569. %                                                                             %
  1570. %                                                                             %
  1571. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1572. %
  1573. %  Function ExecuteFtp executes the FTP program as a child process.
  1574. %
  1575. %  The format of the ExecuteFtp routine is:
  1576. %
  1577. %    ExecuteFtp(host_name,port)
  1578. %
  1579. %  A description of each parameter follows:
  1580. %
  1581. %    o host_name:  Specifies a pointer to a character array that contains the
  1582. %      name of the host to establish a connection to a FTP server.
  1583. %
  1584. %    o port:  Specifies a port number.  If the port number is NULL, xtp
  1585. %      attempts to contact a FTP server at the default port.
  1586. %
  1587. %
  1588. %
  1589. */
  1590. static void ExecuteFtp(host_name,port)
  1591. char
  1592. X  *host_name,
  1593. X  *port;
  1594. {
  1595. X  int
  1596. X    slave;
  1597. X
  1598. X  struct sigaction
  1599. X    action;
  1600. X
  1601. X  struct termios
  1602. X    attributes;
  1603. X
  1604. X  /*
  1605. X    Get slave tty line.
  1606. X  */
  1607. X  action.sa_handler=SIG_IGN;
  1608. X  (void) sigemptyset(&action.sa_mask);
  1609. X  action.sa_flags=0;
  1610. X  (void) sigaction(SIGTSTP,&action,(struct sigaction *) NULL);
  1611. X  if (isatty(STDIN_FILENO))
  1612. X    (void) setsid();
  1613. X  slave=open(slave_tty,O_RDWR | O_NOCTTY);
  1614. X  if (slave < 0)
  1615. X    Error("unable to open slave pseudo-terminal",slave_tty);
  1616. X  /*
  1617. X    Condition slave tty line.
  1618. X  */
  1619. X  (void) tcgetattr(slave,&attributes);
  1620. X  attributes.c_cflag|=HUPCL;
  1621. X  attributes.c_lflag&=(~(ICANON | ECHO));
  1622. X  attributes.c_oflag&=(~OPOST);
  1623. X  (void) tcflush(slave,TCIFLUSH);
  1624. X  (void) tcsetattr(slave,TCSANOW,&attributes);
  1625. X  /*
  1626. X    Execute FTP program as a child process.
  1627. X  */
  1628. X  (void) close(master);
  1629. X  (void) dup2(slave,STDIN_FILENO);
  1630. X  (void) dup2(slave,STDOUT_FILENO);
  1631. X  (void) dup2(slave,STDERR_FILENO);
  1632. X  (void) close(slave);
  1633. X  (void) execlp("ftp","ftp","-n","-i","-g","-v",host_name,port,(char *) 0);
  1634. X  perror("ftp");
  1635. X  (void) kill(0,SIGTERM);
  1636. }
  1637. X
  1638. /*
  1639. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1640. %                                                                             %
  1641. %                                                                             %
  1642. %                                                                             %
  1643. %   G e t P a s s w o r d                                                     %
  1644. %                                                                             %
  1645. %                                                                             %
  1646. %                                                                             %
  1647. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1648. %
  1649. %  Function GetPassword prompts the user for a password.  The password is
  1650. %  not echoed on the terminal.
  1651. %
  1652. %  The format of the GetPassword routine is:
  1653. %
  1654. %    password=GetPassword(prompt)
  1655. %
  1656. %  A description of each parameter follows:
  1657. %
  1658. %    o password:  Specifies a pointer to a character array that contains
  1659. %      accepted from the user.
  1660. %
  1661. %    o prompt:  Specifies a pointer to a character array that contains
  1662. %      a message to display to the user.
  1663. %
  1664. %
  1665. */
  1666. static char *GetPassword(prompt)
  1667. char
  1668. X  *prompt;
  1669. {
  1670. X  static char
  1671. X    password[2048];
  1672. X
  1673. X  struct termios
  1674. X    attributes;
  1675. X
  1676. X  (void) fprintf(stdout,"%s",prompt);
  1677. X  (void) fflush(stdout);
  1678. X  (void) tcgetattr(STDIN_FILENO,&attributes);
  1679. X  attributes.c_lflag&=(~ECHO);
  1680. X  (void) tcsetattr(STDIN_FILENO,TCSANOW,&attributes);
  1681. X  gets(password);
  1682. X  attributes.c_lflag|=ECHO;
  1683. X  (void) tcsetattr(STDIN_FILENO,TCSANOW,&attributes);
  1684. X  (void) fprintf(stdout,"\n");
  1685. X  return(password);
  1686. }
  1687. X
  1688. /*
  1689. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1690. %                                                                             %
  1691. %                                                                             %
  1692. %                                                                             %
  1693. %   G e t P s e u d o T e r m i n a l                                         %
  1694. %                                                                             %
  1695. %                                                                             %
  1696. %                                                                             %
  1697. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1698. %
  1699. %  Function GetPseudoTerminal returns a master/slave pair of pseudo-terminals.
  1700. %
  1701. %  The format of the GetPseudoTerminal routine is:
  1702. %
  1703. %    GetPseudoTerminal()
  1704. %
  1705. %
  1706. */
  1707. static void GetPseudoTerminal()
  1708. {
  1709. X  char
  1710. X    master_tty[16];
  1711. X
  1712. X  register char
  1713. X    *bank,
  1714. X    *cp;
  1715. X
  1716. X  struct stat
  1717. X    info;
  1718. X
  1719. X  for (bank="pqrs"; *bank; bank++)
  1720. X  {
  1721. X    (void) sprintf(master_tty,"/dev/pty%c0",*bank);
  1722. X    if (stat(master_tty,&info) < 0)
  1723. X      break;
  1724. X    for (cp="0123456789abcdef"; *cp; cp++)
  1725. X    {
  1726. X      (void) sprintf((char *) master_tty,"/dev/pty%c%c",*bank,*cp);
  1727. X      master=open(master_tty,O_RDWR);
  1728. X      if (master >= 0)
  1729. X        {
  1730. X          /*
  1731. X            Verify slave side is usable.
  1732. X          */
  1733. X          (void) sprintf(slave_tty,"/dev/tty%c%c",*bank,*cp);
  1734. X          if (access(slave_tty,R_OK | W_OK) == 0)
  1735. X            {
  1736. X              struct termios
  1737. X                attributes;
  1738. X
  1739. X              /*
  1740. X                Condition master tty line.
  1741. X              */
  1742. X              (void) tcgetattr(master,&attributes);
  1743. X              attributes.c_lflag&=(~(ICANON | ECHO));
  1744. X              (void) tcsetattr(master,TCSANOW,&attributes);
  1745. X              return;
  1746. X            }
  1747. X          (void) close(master);
  1748. X        }
  1749. X    }
  1750. X  }
  1751. X  Error("All network ports in use",(char *) NULL);
  1752. }
  1753. X
  1754. /*
  1755. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1756. %                                                                             %
  1757. %                                                                             %
  1758. %                                                                             %
  1759. %   M a k e D i r e c t o r y                                                 %
  1760. %                                                                             %
  1761. %                                                                             %
  1762. %                                                                             %
  1763. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1764. %
  1765. %  Function MakeDirectory checks each component of a directory path and if it
  1766. %  does not exist, creates it.
  1767. %
  1768. %  The format of the MakeDirectory routine is:
  1769. %
  1770. %    MakeDirectory(directory)
  1771. %
  1772. %  A description of each parameter follows:
  1773. %
  1774. %    o directory:  Specifies a pointer to a character array that contains
  1775. %      the name of the directory to create.
  1776. %
  1777. %
  1778. */
  1779. static int MakeDirectory(directory)
  1780. char
  1781. X  *directory;
  1782. {
  1783. X  register char
  1784. X    *p;
  1785. X
  1786. X  struct stat
  1787. X    info;
  1788. X
  1789. X  /*
  1790. X    Determine first component of the directory.
  1791. X  */
  1792. X  p=strrchr(directory,'/');
  1793. X  if ((p == (char *) NULL) || (p == directory))
  1794. X    return(False);
  1795. X  *p='\0';
  1796. X  if (lstat(directory,&info) < 0)
  1797. X    {
  1798. X      /*
  1799. X        Path component does not exist;  create it.
  1800. X      */
  1801. X      if (MakeDirectory(directory) == 0)
  1802. X        if (mkdir(directory,(mode_t) 0777) >= 0)
  1803. X          {
  1804. X            *p='/';
  1805. X            return(False);
  1806. X          }
  1807. X    }
  1808. X  else
  1809. X    if (S_ISDIR(info.st_mode))
  1810. X      {
  1811. X        /*
  1812. X          Path component already exists.
  1813. X        */
  1814. X        *p='/';
  1815. X        return(False);
  1816. X      }
  1817. X  /*
  1818. X    Path component is a file not a directory.
  1819. X  */
  1820. X  *p='/';
  1821. X  return(True);
  1822. }
  1823. X
  1824. /*
  1825. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1826. %                                                                             %
  1827. %                                                                             %
  1828. %                                                                             %
  1829. %   P r i n t R e q u e s t                                                   %
  1830. %                                                                             %
  1831. %                                                                             %
  1832. %                                                                             %
  1833. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1834. %
  1835. %  Function PrintRequest prints a file on the remote FTP server.
  1836. %
  1837. %  The format of the PrintRequest routine is:
  1838. %
  1839. %    PrintRequest(filename,verbose)
  1840. %
  1841. %  A description of each parameter follows:
  1842. %
  1843. %    o filename:  Specifies a pointer to a character array that contains
  1844. %      the name of the file to print.
  1845. %
  1846. %    o verbose: An unsigned integer.  A value other than zero dhows all
  1847. %      responses from the remote server.
  1848. %
  1849. %
  1850. */
  1851. static void PrintRequest(filename,verbose)
  1852. char
  1853. X  *filename;
  1854. X
  1855. unsigned int
  1856. X  verbose;
  1857. {
  1858. X  char
  1859. X    command[2048],
  1860. X    *response;
  1861. X
  1862. X  /*
  1863. X    get remote-file [ - | < |zcat > ].
  1864. X  */
  1865. X  (void) sprintf(command,"get %s",filename);
  1866. X  if (strcmp(filename+strlen(filename)-2,".Z"))
  1867. X    (void) strcat(command," -\r");
  1868. X  else
  1869. X    (void) strcat(command," |zcat\r");
  1870. X  (void) write(master,command,strlen(command));
  1871. X  (void) fprintf(stdout,"%s:\n",filename);
  1872. X  while (response=Wait())
  1873. X    if (status == 0)
  1874. X      (void) fprintf(stdout,"%s\n",response);
  1875. X    else
  1876. X      if ((status == 5) || verbose)
  1877. X        (void) fprintf(stderr,"%s\n",response);
  1878. }
  1879. X
  1880. /*
  1881. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1882. %                                                                             %
  1883. %                                                                             %
  1884. %                                                                             %
  1885. %   P r o c e s s R e q u e s t                                               %
  1886. %                                                                             %
  1887. %                                                                             %
  1888. %                                                                             %
  1889. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1890. %
  1891. %  Function ProcessRequest first records any file in the current directory
  1892. %  of the remote FTP server or any of its subdirectories.  Next each filename
  1893. %  is either accepted or rejected based on a user specified regular
  1894. %  expresssion.  If any files match the regular expression, its filename is
  1895. %  listed, it is printed, or it is retrieved as specified on the command line.
  1896. %
  1897. %  The format of the ProcessRequest routine is:
  1898. %
  1899. %    ProcessRequest(prune,verbose)
  1900. SHAR_EOF
  1901. true || echo 'restore of ImageMagick/xtp/xtp.c failed'
  1902. fi
  1903. echo 'End of  part 3'
  1904. echo 'File ImageMagick/xtp/xtp.c is continued in part 4'
  1905. echo 4 > _shar_seq_.tmp
  1906. exit 0
  1907. exit 0 # Just in case...
  1908.