home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume26 / cforms / part02 (.txt) < prev    next >
LaTeX Document  |  1992-05-18  |  39KB  |  1,140 lines

  1. Newsgroups: comp.sources.unix
  2. From: lab@techno.sth.cgl.se (Lars Berntzon)
  3. Subject: v26i057: cforms - forms management front end for curses(3), Part02/03
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6. Submitted-By: lab@techno.sth.cgl.se (Lars Berntzon)
  7. Posting-Number: Volume 26, Issue 57
  8. Archive-Name: cforms/part02
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line, then unpack
  11. # it by saving it into a file and typing "sh file".  To overwrite existing
  12. # files, type "sh file -c".  You can also feed this as standard input via
  13. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  14. # will see the following message at the end:
  15. #        "End of archive 2 (of 3)."
  16. # Contents:  doc/cforms.tex src/get_field.c src/output.c src/token.c
  17. # Wrapped by vixie@cognition.pa.dec.com on Tue May 19 19:14:29 1992
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. if test -f 'doc/cforms.tex' -a "${1}" != "-c" ; then 
  20.   echo shar: Will not clobber existing file \"'doc/cforms.tex'\"
  21. echo shar: Extracting \"'doc/cforms.tex'\" \(13964 characters\)
  22. sed "s/^X//" >'doc/cforms.tex' <<'END_OF_FILE'
  23. X% LATEX Documentation for CForms
  24. X% By Lars Berntzon
  25. X% $Log:    cforms.tex,v $
  26. X% Revision 1.2  92/01/25  18:08:54  lasse
  27. X% Adde how to compile
  28. X% Revision 1.1  92/01/19  12:41:08  lasse
  29. X% Initial revision
  30. X\newcommand{\synopsys}[1]{\verb!\newline
  31. XSynopsys: {#1}!
  32. X\documentstyle{article}
  33. X\title{CForms v 1.0}
  34. X\author{Lars Berntzon, E-Mail: lab@cgl.se}
  35. X\begin{document}
  36. X\maketitle
  37. X\section{Introduction}
  38. X    CForms is a formular manager for building applications to be used for
  39. X    many types of terminals though it uses the {\em curses} library.
  40. X    CForms is built up by a language that consists of the objects: modules,
  41. X    pictures, fields, literals and events.
  42. X    An application is built by one or more modules that contains one or more
  43. X    pictures that handles the various functions in the application.
  44. X    Each picture may contain any number of fields and text literal
  45. X    that describes the appearance of the picture.
  46. X    Fields are defined by their name and may be specified with any type,
  47. X    size, special attributes and event handling functions.
  48. X    CForms may be intermixed with C-code modules in any way.
  49. X\section{Language description}
  50. X     Currently you can only have one module (file) with CForms language,
  51. X    but i plan to make a CForms 'linker' and thus make it possible to
  52. X    have multiple files.
  53. X    The language is not case sensitive exept thoose parts
  54. X    that are pure C-code (in events- and ccode statements).
  55. X\subsection{Viewports}
  56. X    To create a picture you first need to create a viewport, wich 
  57. X    describes the size and position on the real screen where the picture
  58. X    should appear. A viewport is defined by its name, wich later should
  59. X    be referenced in the picture. Several pictures may share the same
  60. X    viewport.
  61. X    Syntax for a viewport is:
  62. X    \begin{verbatim}
  63. X        VIEWPORT <name> {
  64. X            POS <column>, <row>;
  65. X            SIZE <width>, <height>;
  66. X        }
  67. X    \end{verbatim}
  68. X    Example:
  69. X    \begin{verbatim}
  70. X        Viewport stdscreen {
  71. X            Pos 1,1;
  72. X            Size 80, 24;
  73. X        }
  74. X    \end{verbatim}
  75. X\subsection{CCode}
  76. X    The CCode statement introduces a C-code block that may contain any
  77. X    code such as global variables, functions, preprocessor statements.
  78. X    This means that there is no need to have separated form-files and
  79. X    C-files with support functions. Ccodes may only be used in outer
  80. X    scopes, i.e. not inside pictures, literals or fields.
  81. X    Syntax for Ccode is:
  82. X        \begin{verbatim}
  83. X        CCODE {
  84. X            <Any C code>
  85. X        }
  86. X        \end{verbatim}
  87. X    Example:
  88. X        \begin{verbatim}
  89. X        CCode {
  90. X            cleanup()
  91. X            {
  92. X                free_all_mem();
  93. X                cforms_end();
  94. X                exit();
  95. X            }
  96. X        }
  97. X        \end{verbatim}
  98. X\subsection{Pictures}
  99. X    A picture is what shows up on the terminal when the application is
  100. X    running. Pictures contains fields - which are places for input or
  101. X    output, literals - which are static texts and events -
  102. X    events doesn't show but defines C-code functions to be called when
  103. X    certain things happens. Events specified in pictures are actually
  104. X    used by fields, but they are automatically specified for all fields
  105. X    in that pictures (unless specifically turned off), in other worlds a
  106. X    default event for all fields.
  107. X    A pictures is defined by its name, and the first picture to be started
  108. X    in the application is determined in the main routine (or a descendant)
  109. X    through the function {\em pic\_call}.
  110. X    Syntax for a picture is:
  111. X    \begin{verbatim}
  112. X        PICTURE <picture-name> VIEWPORT <viewport-name> {
  113. X            <literals>   \
  114. X            <fields>      > in any order
  115. X            <events>     /
  116. X        }
  117. X    \end{verbatim}
  118. X    Example:
  119. X    \begin{verbatim}
  120. X        Picture main Viewport stdscreen {
  121. X            Literal 10, 10, "Welcome, enter your name: ";
  122. X            Field Name {
  123. X                Pos +0, +1;
  124. X                Type Char(10);
  125. X            }
  126. X        }
  127. X    \end{verbatim}
  128. X\subsection{Fields}
  129. X    Fields are placesholders in pictures that may be used to input from
  130. X    operator and/or as output from the application. A field may be of
  131. X    many kind of types and sizes. Fields can also contain events that
  132. X    will be called when the specified event occurs. It is also possible
  133. X    to specify literal text to appear immediately before and immediately
  134. X    after the actual field, this makes it possible to have text belonging
  135. X    to fields that are not depending of the fields position.
  136. X    The position of a field may be specified in absolute- or relative 
  137. X    coordinates. For relative coordinates the column- and row number is
  138. X    prepended by a minus or a plus sign to indikate positive or negative
  139. X    relative position.
  140. X    Finally it is possible to specify a couple of modifiers for the field that
  141. X    modifies adjustment, visibility, protection e.t.c.
  142. X    Valid types for a field is:
  143. X    \begin{itemize}
  144. X       \item{INT} Field may only contain digits.
  145. X       \item{STR} Field may only contain alphanumeric characters.
  146. X       \item{CHAR} Field may contain any printable character.
  147. X    \end{itemize}
  148. X    The size of a field is by default 1, but may be altered as a number
  149. X    within brackets after the type.
  150. X    Valid modifiers are:
  151. X    \begin{itemize}
  152. X        \item{PROTECTED}    - Field may not be altered.
  153. X        \item{UPPERCASE}    - All alpha characters are in uppercase.
  154. X    \end{itemize}
  155. X    Syntax for a field is:
  156. X    \begin{verbatim}
  157. X        FIELD <name> {
  158. X            <type> [(<size>)];
  159. X            POS [+-]<column>, [+-]<row>;
  160. X            LVALUE "<left value>";
  161. X            RVALUE "<right value>";
  162. X            [UPPERCASE;]
  163. X            [PROTECTED;]
  164. X        }
  165. X    \end{verbatim}
  166. X    Example:
  167. X    \begin{verbatim}
  168. X        Field adress {
  169. X            Pos 20, +1;
  170. X            Type Char(20);
  171. X            LValue "Adress: ";
  172. X            Uppercase;
  173. X        }
  174. X    \end{verbatim}
  175. X\subsection{Literals}
  176. X    Literals is static text to be visualized in the picture, literals
  177. X    is below fields if a collission should occur. Syntax of a literal
  178. X    is:
  179. X    \begin{verbatim}
  180. X        Literal [+-]<column>, [+-]<row>, "<text>";
  181. X    \end{verbatim}
  182. X    Example:
  183. X    \begin{verbatim}
  184. X        Literal +0, +1, "List of persons";
  185. X    \end{verbatim}
  186. X\subsection{Events}
  187. X    Events are used to define functions keys and other special cases for eg.
  188. X    refresh display and so on. An event is specified by its event type
  189. X    and either a block of C-code to execute when the event occurres, or the
  190. X    word 'forget' wich means that the specified event should be disabled for
  191. X    this field.
  192. X    Type of events is:
  193. X    \begin{itemize}
  194. X       \item[KEY] A key has been pressed. An event of the type KEY must 
  195. X              have one of the following modifiers:
  196. X       \begin{itemize}
  197. X           \item[F0 - F20 -] Function keys
  198. X           \item[UP -] Up arrow
  199. X           \item[DOWN -] Down arrow
  200. X           \item[LEFT -] Left arrow
  201. X           \item[RIGHT -] Right arrow
  202. X           \item[CR -] Carriage return
  203. X           \item[BS -] Backspace
  204. X           \item[TAB -] Horizontal tab
  205. X           \item[FIND -] Search
  206. X           \item[INSERT -] Insert
  207. X       \end{itemize}
  208. X       \item[REFRESH] Refresh the picture
  209. X       \item[DRAW] Only available from pictures, is called
  210. X                   when a pictures is first drawn.
  211. X       \item[LEFT] When trying to move to the left of the field
  212. X       \item[RIGHT] When trying to move to the left of the field
  213. X       \item[ENTRY] When field is entered
  214. X       \item[EXIT] When field is left
  215. X    \end{itemize}
  216. X        
  217. X    Syntax for an event is:
  218. X    \begin{verbatim}
  219. X        EVENT <type> [<type modifier>] {
  220. X            <C-code statements>
  221. X        }
  222. X    \end{verbatim}
  223. X    \begin{verbatim}
  224. X        EVENT <type> [<type modifier>] FORGET;
  225. X    \end{verbatim}
  226. X    Example:
  227. X    \begin{verbatim}
  228. X        Event Entry {
  229. X            fld_set(current.field, "X");
  230. X        }
  231. X        Event Key DOWN  {
  232. X            fld_move(fld_down(current.field));
  233. X        }
  234. X    \end{verbatim}
  235. X\section{EVENT and CCODE programing}
  236. X    For all event- and ccode blocks the developer can use a set
  237. X    library functions that comes with cforms. Most functions returning
  238. X    integers returns ether OK or FAIL exept for those like fld\_len that
  239. X    returns the value expected. Those returning pointers return NULL
  240. X    uppon failure.
  241. X    This is a list and a description of all functions:        
  242. X    \subsection{Start/stop functions}
  243. X         \subsubsection{cforms\_init} Initiate CForms, this must be done
  244. X        before any cforms functions can be called.
  245. X            \synopsys{int cforms\_init(void)}
  246. X        \subsubsection{cforms\_end} Stop CForms.
  247. X        \synopsys{int cforms\_end(void)}
  248. X     \subsection{Picture functions}
  249. X         \subsubsection{pic\_call} Call picture.
  250. X           \synopsys{int pic\_call(struct picture *, field *)}\\
  251. X        Where picture is a pointer to the picture to call and field
  252. X        is where the cursor lands on, NULL means the first field in
  253. X        picture.
  254. X        \subsubsection{pic\_clear} Clear all fields for picture.
  255. X        \synopsys{int pic\_clear(struct picture *)}\\
  256. X        If picture is NULL current.picture is cleared.
  257. X        \subsubsection{pic\_leave} Leave current picture after current
  258. X        event has finished.
  259. X        \synopsys{int pic\_leave(void)}
  260. X        \subsubsection{picture} Get picture with name.
  261. X        \synopsys{struct picture *picture(char *fmt, ...)}\\
  262. X        Returns a pointer to a picture with the name generated
  263. X        with 'fmt' and its arguments the same way that printf works.
  264. X    \subsection{Field functions}
  265. X        \subsubsection{field} Get field with name
  266. X        \synopsys{struct field *field(char *fmt, ...)}\\
  267. X        Returns a pointer to a field with the name generated
  268. X        with 'fmt' and its arguments the same way that printf works.
  269. X        If the field name is prepended by the picture name and a
  270. X        colon, i.e.  "picture:field", a field can be found in another
  271. X        picture than current.picture.
  272. X        \subsubsection{fld\_isempty} Check if field is empty, i.e.
  273. X        full of spaces, tabs or null.
  274. X        \synopsys{int fld\_isempty(struct field *)}\\
  275. X        Returns TRUE or FALSE condition.
  276. X        \subsubsection{fld\_first} Find first field of picture.
  277. X        \synopsys{struct field *fld\_first(void)}
  278. X        \subsubsection{fld\_last} Find last field of picture.
  279. X        \synopsys{struct field *fld\_last(void)}
  280. X        \subsubsection{fld\_next} Find next field for picture.
  281. X        \synopsys{struct field *fld\_next(struct field *)}\\
  282. X        Returns the field after field given by argument (or
  283. X        current.field if NULL).
  284. X        \subsubsection{fld\_previous} Find previous field for picture.
  285. X        \synopsys{struct field *fld\_previous(struct field *)}\\
  286. X        Returns the field berfore field given by argument (or
  287. X        current.field if NULL).
  288. X        \subsubsection{fld\_left} Find left field.
  289. X        \synopsys{struct field *fld\_left(struct field *)}\\
  290. X        Returns the field to the left of the field given by argument
  291. X        (or current.field if NULL).
  292. X        \subsubsection{fld\_right} Find right field.
  293. X        \synopsys{struct field *fld\_right(struct field *)}\\
  294. X        Returns the field to the right of the field given by argument
  295. X        (or current.field if NULL).
  296. X        \subsubsection{fld\_up} Find field above current.
  297. X        \synopsys{struct field *fld\_up(struct field *)}\\
  298. X        Returns the field above the field given by argument
  299. X        (or cur\-rent.\-field if\- NULL).
  300. X        \subsubsection{fld\_down} Find field below current.
  301. X        \synopsys{struct field *fld\_down(struct field *)}\\
  302. X        Returns the field below the field given by argument
  303. X        (or current.\-field if\- NULL).
  304. X        \subsubsection{fld\_set} Set value for field.
  305. X        \synopsys{int fld\_set(struct field *, char *)}\\
  306. X        If field is NULL set value for current.field.
  307. X        \subsubsection{fld\_nset} Set value for field but max n chars.
  308. X        \synopsys{int fld\_nset(struct field *, char *)}\\
  309. X        If field is NULL set value for current.field.
  310. X        \subsubsection{fld\_get} Get value of field.
  311. X        \synopsys{char *fld\_get(struct field *)}\\
  312. X        If field is NULL get value for current.field.
  313. X        \subsubsection{fld\_len} Return length of field.
  314. X        \synopsys{int fld\_len(struct field *)}\\
  315. X        If field is NULL return length for current.field.
  316. X        \subsubsection{fld\_ismodified} Return true if field has been
  317. X        modified since last fld\_set or fld\_nset.
  318. X        \synopsys{int fld\_ismodified(struct field *)}\\
  319. X        If field is NULL return modified for current.field.
  320. X        \subsubsection{fld\_touch} Make field not modified.
  321. X        \synopsys{int fld\_touch(struct field *)}\\
  322. X        If field is NULL touch current.field.
  323. X     \subsection{General functions}
  324. X         \subsubsection{message} Give message (line 24).
  325. X        \synopsys{int message(char *fmt, ...)}
  326. X        \subsubsection{strequ} Compare two strings, but case insensitive.
  327. X        \synopsys{int strequ(char *s1, char *s2)}
  328. X    \subsection{Global variables}
  329. X        \subsubsection{current.picture} Allways points to current picture
  330. X        (can be NULL).
  331. X        \synopsys{struct picture *current.picture}
  332. X        \subsubsection{current.field} Allways points to current field
  333. X        (can be NULL).
  334. X        \synopsys{struct field *current.field}
  335. X\section{How to compile and install CForms}
  336. XWhen you have unpacked the CForms archive you just do cd to the directory
  337. Xwhere you unpacked it and change the DEST-variable in the Makefile to
  338. Xwhere you want CForms installed.
  339. XAfter that you should do a 'make' followed by an 'make install'.
  340. XYou can also compile the example application in the example subdirectory
  341. Xby doing 'make example', look it up to see what an application might look
  342. Xlike.
  343. X\section{How to compile CForms applications}
  344. XLets say you just installed CForms with DEST set to {\em /usr/local},
  345. Xthat means that the CForms compiler resides in /usr/local/bin, the
  346. Xcforms include file resides in /usr/local/include and the library
  347. Xlibcforms.a in /usr/local/lib, then this is how to compile a CForms
  348. Xapplication:
  349. XFirst you run the CForms compiler, {\em cfc}, on your inputfile:
  350. X    \begin{verbatim}
  351. X    cfc <yourfile>
  352. X    \end{verbatim}
  353. XThis will generate the compiler output file, {\em cforms.c}. That file
  354. Xshould be compiled with you ordinary c-compiler by doing something like:
  355. X    \begin{verbatim}
  356. X    cc -o <yourapp> -I/usr/local/include -L/usr/local/lib \
  357. X         cforms.c -lcforms -lcurses
  358. X    \end{verbatim}
  359. XObserve that the -L flag must be there beccause the cforms library is in
  360. X/usr/\-local/\-lib.
  361. XNow you should be able to run you application.
  362. X\newpage
  363. X\tableofcontents
  364. X\end{document}
  365. END_OF_FILE
  366. if test 13964 -ne `wc -c <'doc/cforms.tex'`; then
  367.     echo shar: \"'doc/cforms.tex'\" unpacked with wrong size!
  368. # end of 'doc/cforms.tex'
  369. if test -f 'src/get_field.c' -a "${1}" != "-c" ; then 
  370.   echo shar: Will not clobber existing file \"'src/get_field.c'\"
  371. echo shar: Extracting \"'src/get_field.c'\" \(6000 characters\)
  372. sed "s/^X//" >'src/get_field.c' <<'END_OF_FILE'
  373. X/*******************************************************************************
  374. X *        G E T _ F I E L D . C
  375. X *        ---------------------
  376. X * Description:
  377. X *    Compiles a field statement.
  378. X * Included functions:
  379. X *    get_field    - Does the job.
  380. X * Revision:
  381. X *    Ver    Date    By        Reason
  382. X *    ---    ----    --        ------
  383. X *    1.00    900625    Lars Berntzon    Created
  384. X ******************************************************************************/
  385. X#include <stdio.h>
  386. X#include <ctype.h>
  387. X#include <string.h>
  388. X#include "token.h"
  389. X#include "comp.h"
  390. X#define isnormal(ch) (isalnum(ch) || (ch) == '_')
  391. Xstatic int found_pos();
  392. Xstatic int found_event();
  393. Xstatic int found_lvalue();
  394. Xstatic int found_rvalue();
  395. Xstatic int found_type();
  396. Xstatic int found_protected();
  397. Xstatic int found_uppercase();
  398. Xstatic struct lookup_s lookup[] = {
  399. X    "LVALUE",     found_lvalue,
  400. X    "RVALUE",     found_rvalue,
  401. X    "POS",     found_pos,
  402. X    "EVENT",     found_event,
  403. X    "TYPE",     found_type,
  404. X    "PROTECTED", found_protected,
  405. X    "UPPERCASE", found_uppercase
  406. Xstruct field *get_field()
  407. X    char token[TOKENSIZE];
  408. X    struct field *fp = NULL;
  409. X    int i;
  410. X    
  411. X    if (GetTokNC(token) == NULL || !isnormal(token[0])) {
  412. X        error("expected name of field");
  413. X        return NULL;
  414. X    }
  415. X    
  416. X    fp = memalloc(sizeof *fp);
  417. X    link_name(&fp->link, token);
  418. X    
  419. X    if (GetTokNC(token) == NULL || strcmp(token, "{")) {
  420. X        error("expected '{'");
  421. X        unget_field(fp);
  422. X        return NULL;
  423. X    }
  424. X    
  425. X    while(GetTokNC(token) != NULL) {
  426. X    if(strcmp(token, "}") == 0) break;
  427. X    else if (strcmp(token, "{") == 0) {
  428. X        UnGetTok("{");
  429. X        skip_stmt();
  430. X        continue;
  431. X    for(i = 0; i < N_CMDS; i++) {
  432. X        if (strequ(token, lookup[i].cmd) == 0) break;
  433. X    if (i < N_CMDS) {
  434. X        if ((*lookup[i].func)(fp) != OK) {
  435. X            unget_field(fp);
  436. X            return NULL;
  437. X        }
  438. X    else {
  439. X        error("unknown token for field");
  440. X    }
  441. X    if (fp->lvalue && fp->pos.x - (int) strlen(fp->lvalue) < 1) {
  442. X        error("field has position to far left");
  443. X    }
  444. X    if (fp->rvalue && fp->pos.x + fp->len +  (int) strlen(fp->rvalue) >= 80) {
  445. X        error("field has position to far left");
  446. X    }
  447. X    if (fp->type == NULL) {
  448. X        error("undefined type for field");
  449. X        unget_field(fp);
  450. X        return NULL;
  451. X    }
  452. X    return fp;
  453. Xstruct field *unget_field(struct field *fp)
  454. X    struct field *next;
  455. X    struct event *ep;
  456. X    if (fp == NULL) return NULL;
  457. X    next = (struct field *)fp->link.next;
  458. X    
  459. X    for(ep = fp->event; ep != NULL; ep = unget_event(ep))
  460. X    if (fp->link.name) free(fp->link.name);
  461. X    if (fp->lvalue) free(fp->lvalue);
  462. X    if (fp->rvalue) free(fp->rvalue);
  463. X    free(fp);
  464. X    return next;
  465. Xstatic int found_lvalue(fp)
  466. X    struct field *fp;
  467. X    char token[TOKENSIZE];
  468. X    
  469. X    if (GetTokNC(token) == NULL || token[0] != '"') {
  470. X        error("expected lvalue");
  471. X        return FAIL;
  472. X    }
  473. X    token[strlen(token) - 1] = 0;
  474. X    
  475. X    fp->lvalue = memalloc(strlen(token));
  476. X    strcpy(fp->lvalue, token + 1);
  477. X    if (GetTokNC(token) == NULL || strcmp(token, ";")) {
  478. X        error("expected ';'");
  479. X        return FAIL;
  480. X    }
  481. X    return OK;
  482. Xstatic int found_rvalue(fp)
  483. X    struct field *fp;
  484. X    char token[TOKENSIZE];
  485. X    
  486. X    if (GetTokNC(token) == NULL || token[0] != '"') {
  487. X        error("expected rvalue");
  488. X        return FAIL;
  489. X    }
  490. X    token[strlen(token) - 1] = 0;
  491. X    
  492. X    fp->rvalue = memalloc(strlen(token));
  493. X    strcpy(fp->rvalue, token + 1);
  494. X    if (GetTokNC(token) == NULL || strcmp(token, ";")) {
  495. X        error("expected ';'");
  496. X        return FAIL;
  497. X    }
  498. X    return OK;
  499. Xstatic int found_pos(fp)
  500. X    struct field *fp;
  501. X    char token[TOKENSIZE];
  502. X    
  503. X    if (GetPos(&fp->pos.x, & fp->pos.y) != OK) return FAIL;
  504. X    
  505. X    if (GetTokNC(token) == NULL || strcmp(token, ";")) {
  506. X        error("expected ';'");
  507. X        return FAIL;
  508. X    }
  509. X    return OK;
  510. Xstatic int found_event(fp)
  511. X    struct field *fp;
  512. X    struct event *ep;
  513. X    
  514. X    if ((ep = get_event()) == NULL) return FAIL;
  515. X    
  516. X    link((struct link **)&fp->event, &ep->link, TYPE_EVENT);
  517. X    
  518. X    return OK;
  519. Xstatic int found_type(fp)
  520. X    struct field *fp;
  521. X    char token[TOKENSIZE];
  522. X    int i;
  523. X    
  524. X    static struct {
  525. X        char *name;
  526. X        char *code;
  527. X    } type[] = {
  528. X        "INT",     "FLD_INT",
  529. X        "CHAR",  "FLD_STR",
  530. X        "ALNUM", "FLD_ALNUM",
  531. X        NULL, NULL
  532. X    };
  533. X    
  534. X    if (GetTokNC(token) == NULL) {
  535. X        error("unexpected end of file for field");
  536. X        return FAIL;
  537. X    }
  538. X    
  539. X    for(i = 0; type[i].name != NULL; i++) {
  540. X        if (strequ(token, type[i].name) == 0) break;
  541. X    }
  542. X    if (type[i].name == NULL) {
  543. X        error("unknown type for field");
  544. X        return FAIL;
  545. X    }
  546. X    
  547. X    fp->type = type[i].code;
  548. X    fp->len = 1;
  549. X    
  550. X    if (GetTokNC(token) == NULL) {
  551. X        error("unexpected end of file for field");
  552. X        return FAIL;
  553. X    }
  554. X    
  555. X    if (strcmp(token, ";") == 0) return OK;
  556. X    
  557. X    if (strcmp(token, "(") != 0) {
  558. X        error("expected '(' or ';' after field type");
  559. X        return FAIL;
  560. X    }
  561. X    
  562. X    if (GetTokNC(token) == NULL || !isdigit(token[0])) {
  563. X        error("field size must be integer");
  564. X        return FAIL;
  565. X    }
  566. X    
  567. X    fp->len = atoi(token);
  568. X    
  569. X    if (GetTokNC(token) == NULL || strcmp(token, ")")) {
  570. X        error("expected ')' after field");
  571. X        return FAIL;
  572. X    } 
  573. X    if (GetTokNC(token) == NULL || strcmp(token, ";")) {
  574. X        error("expected ';' after field");
  575. X        return FAIL;
  576. X    }
  577. X    return OK;
  578. Xstatic int found_protected(fp)
  579. X    struct field *fp;
  580. X    char token[TOKENSIZE];
  581. X    
  582. X    fp->flags |= FLD_PROTECTED;
  583. X    
  584. X    if (GetTokNC(token) == NULL) {
  585. X        error("unexpected end of file for field");
  586. X        return FAIL;
  587. X    }
  588. X    if (strcmp(token, ";") != 0) {
  589. X        error("expetced ';'");
  590. X        return FAIL;
  591. X    }
  592. X    
  593. X    return OK;
  594. Xstatic int found_uppercase(fp)
  595. X    struct field *fp;
  596. X    char token[TOKENSIZE];
  597. X    
  598. X    fp->flags |= FLD_UPPERCASE;
  599. X    
  600. X    if (GetTokNC(token) == NULL) {
  601. X        error("unexpected end of file for field");
  602. X        return FAIL;
  603. X    }
  604. X    if (strcmp(token, ";") != 0) {
  605. X        error("expetced ';'");
  606. X        return FAIL;
  607. X    }
  608. X    
  609. X    return OK;
  610. END_OF_FILE
  611. if test 6000 -ne `wc -c <'src/get_field.c'`; then
  612.     echo shar: \"'src/get_field.c'\" unpacked with wrong size!
  613. # end of 'src/get_field.c'
  614. if test -f 'src/output.c' -a "${1}" != "-c" ; then 
  615.   echo shar: Will not clobber existing file \"'src/output.c'\"
  616. echo shar: Extracting \"'src/output.c'\" \(8094 characters\)
  617. sed "s/^X//" >'src/output.c' <<'END_OF_FILE'
  618. X/*******************************************************************************
  619. X *        O U T P U T . C
  620. X *        ---------------
  621. X * Description:
  622. X *    Generates the C-code for CForms.
  623. X * Included functions:
  624. X *    output        - Does the job
  625. X * Revision:
  626. X *    Ver    Date    By        Reason
  627. X *    ---    ----    --        ------
  628. X *    1.00    900627    Lars Berntzon    Created
  629. X ******************************************************************************/
  630. X#include "config.h"
  631. X#include <stdio.h>
  632. X#include <ctype.h>
  633. X#include <string.h>
  634. X#include <assert.h>
  635. X#include "token.h"
  636. X#include "comp.h"
  637. Xvoid output()
  638. X    struct viewport *vp;
  639. X    struct picture *pp;
  640. X    struct field *fp;
  641. X    struct event *ep;
  642. X    struct stmt *sp;
  643. X    struct literal *lp;
  644. X    struct ccode *cp;
  645. X    int n_fields, n_events, n_literals, n_pictures;
  646. X    FILE *out;
  647. X    
  648. X    if ((out = fopen("cforms.c", "w")) == NULL) {
  649. X        fprintf(stderr, "failed to open output file.\n");
  650. X        cleanup(1);
  651. X    }
  652. X    
  653. X    /*
  654. X     * G e n e r a t e   H e a d e r.
  655. X     */
  656. X     
  657. X     fprintf(out, "/* Generated by C-Forms version %s */\n\n", version);
  658. X     fprintf(out, "#include <stdio.h>\n\n");
  659. X     fprintf(out, "#include <curses.h>\n");
  660. X     fprintf(out, "#include \"cforms.h\"\n\n");
  661. X#if 0     
  662. X     /*
  663. X      * C r e a t e   v i e w p o r t s.
  664. X      */
  665. X     if (list.viewport) {
  666. X         fprintf(out, "    /* V i e w p o r t s */\n\n");
  667. X         for(vp = list.viewport; vp != NULL; vp = NEXT_VIEWPORT(vp))
  668. X         {
  669. X             fprintf(out, "WINDOW *win_%s;\n", vp->link.name);
  670. X         }
  671. X         fprintf(out, "\n");
  672. X    }
  673. X#endif
  674. X    
  675. X    /*
  676. X     * C r e a t e   C - c o d e s.
  677. X     */
  678. X    if (list.ccode) fprintf(out, "    /* C - c o d e s */\n\n");
  679. X    for(cp = list.ccode; cp != NULL; cp = NEXT_CCODE(cp)) 
  680. X    {
  681. X        for(sp = cp->stmt; sp != NULL; sp = sp->next) {
  682. X            fprintf(out, "%s\n", sp->txt);
  683. X        }
  684. X        fprintf(out, "\n");
  685. X    }
  686. X    
  687. X    /*
  688. X     * C r e a t e   p i c t u r e s.
  689. X     */
  690. X    if (list.picture) fprintf(out, "    /* P i c t u r e s */\n\n");
  691. X    for(pp = list.picture; pp != NULL; pp = NEXT_PICTURE(pp))
  692. X    {
  693. X        /*
  694. X         * E v e n t s   f o r   a l l   f i e l d s.
  695. X         */
  696. X        n_fields = 0;
  697. X        n_literals = 0;
  698. X        
  699. X    for(fp = pp->field; fp != NULL; fp = NEXT_FIELD(fp))
  700. X    {
  701. X        /* Event routines for field */
  702. X        
  703. X    for(ep = fp->event; ep != NULL; ep = NEXT_EVENT(ep))
  704. X        if (ep->stmt) {
  705. X            fprintf(out, "static void event_%s_%s_%s()\n{\n",
  706. X            pp->link.name, fp->link.name, ep->link.name);
  707. X        for(sp = ep->stmt; sp != NULL; sp = sp->next)
  708. X            fprintf(out, "    %s\n", sp->txt);
  709. X        fprintf(out, "}\n");
  710. X        }
  711. X        /* Event table for field */
  712. X    if (fp->event) {
  713. X        fprintf(out, "static struct event etab_%s_%s[] = {\n",
  714. X            pp->link.name, fp->link.name);
  715. X        for(ep = fp->event; ep != NULL; ep = NEXT_EVENT(ep))
  716. X        {
  717. X            fprintf(out, "    %s, %s, ", ep->type, ep->code);
  718. X            
  719. X            if (ep->stmt) {
  720. X                fprintf(out, "event_%s_%s_%s",
  721. X                    pp->link.name, fp->link.name, ep->link.name);
  722. X            }
  723. X            else {
  724. X                fprintf(out, "NULL");
  725. X            }
  726. X            fprintf(out, "%s\n", NEXT_EVENT(ep) ? "," : "");
  727. X        }
  728. X        fprintf(out, "};\n\n");
  729. X    /* 
  730. X     * F i e l d   d a t a   a r r a y.
  731. X     */
  732. X    fprintf(out, "static char field_%s_%s[%d];\n\n",
  733. X          pp->link.name, fp->link.name, fp->len + 1);
  734. X    fprintf(out, "/***************************************************/\n");
  735. X    }
  736. X    
  737. X    /*
  738. X     * T a b l e   o f   a l l   f i e l d s.
  739. X     */
  740. X    if (pp->field) {
  741. X        fprintf(out, "static struct field ftab_%s[] = {\n", pp->link.name);
  742. X        
  743. X    for(fp = pp->field; fp != NULL; n_fields++, fp = NEXT_FIELD(fp))
  744. X        fprintf(out, "   {\"%s\", ", fp->link.name);
  745. X        fprintf(out, "%s, %d, ", fp->type, fp->len);
  746. X        fprintf(out, "field_%s_%s, ", pp->link.name, fp->link.name);
  747. X        fprintf(out, "%d, %d, \"%s\", \"%s\", ", fp->pos.x, fp->pos.y,
  748. X            fp->lvalue ? fp->lvalue : "", fp->rvalue ? fp->rvalue : "");
  749. X        if (fp->event) {
  750. X            fprintf(out, "etab_%s_%s", pp->link.name, fp->link.name);
  751. X        }
  752. X        else {
  753. X            fprintf(out, "NULL");
  754. X        }
  755. X        for(n_events = 0, ep = fp->event; ep != NULL;
  756. X            n_events++, ep = NEXT_EVENT(ep))
  757. X            ;
  758. X        fprintf(out, ", %d, %d", n_events, fp->flags);
  759. X        fprintf(out, ", 0"); /* Modified flag */
  760. X        fprintf(out, ", NULL"); /* Modified flag */
  761. X        fprintf(out, "}%s", NEXT_FIELD(fp) ? ",\n" : "\n");
  762. X    fprintf(out, "};\n\n");
  763. X    }
  764. X    
  765. X    /*
  766. X     * T a b l e   o f   l i t e r a l s.
  767. X     */
  768. X    if (pp->literal) {
  769. X        fprintf(out, "static struct literal ltab_%s[] = {\n", pp->link.name);
  770. X        for(lp = pp->literal; lp != NULL; n_literals++, lp = NEXT_LITERAL(lp))
  771. X        {
  772. X            fprintf(out, "    %d, %d, \"%s\", %d%s\n",
  773. X                lp->pos.x, lp->pos.y,
  774. X                lp->link.name, lp->display_flags,
  775. X                NEXT_LITERAL(lp) ? "," : "");
  776. X        }
  777. X        fprintf(out, "};\n\n");
  778. X    }
  779. X    
  780. X    /*
  781. X     * E v e n t s   f o r   p i c t u r e.
  782. X     */
  783. X     
  784. X    for(ep = pp->event; ep != NULL; ep = NEXT_EVENT(ep))
  785. X    {
  786. X        if (ep->stmt) {
  787. X        fprintf(out, "static void event_%s_%s()\n{\n",
  788. X            pp->link.name, ep->link.name);
  789. X        for(sp = ep->stmt; sp != NULL; sp = sp->next)
  790. X        {
  791. X            fprintf(out, "    %s\n", sp->txt);
  792. X        }
  793. X        fprintf(out, "}\n\n");
  794. X    }
  795. X    
  796. X    n_events = 0;
  797. X    if(pp->event) {
  798. X        fprintf(out, "static struct event etab_%s[] = {\n", 
  799. X            pp->link.name);
  800. X        for(ep = pp->event; ep != NULL; n_events++, ep = NEXT_EVENT(ep))
  801. X        {
  802. X            fprintf(out, "    %s, %s, ", ep->type, ep->code);
  803. X            
  804. X            if (ep->stmt) {
  805. X                fprintf(out, "event_%s_%s", pp->link.name, ep->link.name);
  806. X            }
  807. X            else {
  808. X                fprintf(out, "NULL");
  809. X            }
  810. X            fprintf(out, "%s\n", NEXT_EVENT(ep) ? "," : "");
  811. X        }
  812. X        fprintf(out, "};\n\n");
  813. X    }
  814. X    }
  815. X    
  816. X    /*
  817. X     * T a b l e   o f   p i c t u r e s.
  818. X     */
  819. X    if(list.picture) {
  820. X        fprintf(out, "static struct picture ptab[] = {\n");
  821. X    }
  822. X    n_pictures = 0;
  823. X    for(pp = list.picture; pp != NULL; n_pictures++, pp = NEXT_PICTURE(pp))
  824. X    {
  825. X        fprintf(out, "    {\"%s\", ", pp->link.name);
  826. X            /* Fields */
  827. X    for(n_fields = 0, fp = pp->field; fp; fp = NEXT_FIELD(fp)) {
  828. X        n_fields++;
  829. X    if (pp->field) {
  830. X        fprintf(out, "ftab_%s, %d, ", pp->link.name, n_fields);
  831. X    else fprintf(out, "NULL, 0, ");
  832. X        /* Literals */
  833. X    for(n_literals = 0, lp = pp->literal; lp; lp = NEXT_LITERAL(lp)) {
  834. X        n_literals++;
  835. X    if (pp->literal) {
  836. X        fprintf(out, "ltab_%s, %d, ", pp->link.name, n_literals);
  837. X    else fprintf(out, "NULL, 0, ");
  838. X        /* Events */
  839. X    for(n_events = 0, ep = pp->event; ep; ep = NEXT_EVENT(ep)) {
  840. X        n_events++;
  841. X    if (pp->event) {
  842. X        fprintf(out, "etab_%s, %d", pp->link.name, n_events);
  843. X    else fprintf(out, "NULL, 0");
  844. X    fprintf(out, ", %d,%d, %d,%d}", pp->viewport->pos.x, pp->viewport->pos.y,
  845. X        pp->viewport->size.x, pp->viewport->size.y);
  846. X    if (NEXT_PICTURE(pp)) {
  847. X        fprintf(out, ",");
  848. X    fprintf(out, "\n");
  849. X    }
  850. X    if(list.picture) {
  851. X        fprintf(out, "};\n\n");
  852. X    }
  853. X    /*
  854. X     * Event functions for module.
  855. X     */
  856. X    for(ep = list.event; ep != NULL; ep = NEXT_EVENT(ep))
  857. X    {
  858. X        if (ep->stmt) {
  859. X        fprintf(out, "static void event_%s()\n{\n", ep->link.name);
  860. X        for(sp = ep->stmt; sp != NULL; sp = sp->next)
  861. X        {
  862. X            fprintf(out, "    %s\n", sp->txt);
  863. X        }
  864. X        fprintf(out, "}\n\n");
  865. X    }
  866. X    n_events = 0;
  867. X    if(list.event) {
  868. X        fprintf(out, "static struct event etab[] = {\n");
  869. X        for(ep = list.event; ep != NULL; n_events++, ep = NEXT_EVENT(ep))
  870. X        {
  871. X            fprintf(out, "    %s, %s, ", ep->type, ep->code);
  872. X            
  873. X            if (ep->stmt) {
  874. X                fprintf(out, "event_%s", ep->link.name);
  875. X            }
  876. X            else {
  877. X                fprintf(out, "NULL");
  878. X            }
  879. X            fprintf(out, "%s\n", NEXT_EVENT(ep) ? "," : "");
  880. X        }
  881. X        fprintf(out, "};\n\n");
  882. X    }
  883. X    fprintf(out, "struct module _module = { ");
  884. X    if (list.picture) fprintf(out, "ptab, %d, ", n_pictures);
  885. X    else fprintf(out, "NULL, 0, ");
  886. X    if (list.event)  fprintf(out, "etab, %d", n_events);
  887. X    else fprintf(out, "NULL, 0");
  888. X    fprintf(out, "};\n");
  889. END_OF_FILE
  890. if test 8094 -ne `wc -c <'src/output.c'`; then
  891.     echo shar: \"'src/output.c'\" unpacked with wrong size!
  892. # end of 'src/output.c'
  893. if test -f 'src/token.c' -a "${1}" != "-c" ; then 
  894.   echo shar: Will not clobber existing file \"'src/token.c'\"
  895. echo shar: Extracting \"'src/token.c'\" \(6503 characters\)
  896. sed "s/^X//" >'src/token.c' <<'END_OF_FILE'
  897. X/*******************************************************************************
  898. X*        T O K E N . C
  899. X*        -------------
  900. X* Description:
  901. X*    Reads tokens from input file. Tokens are the C-stype tokens. It is
  902. X*    allso possible to unget tokens for later recall by GetTok().
  903. X* Included functions:
  904. X*    GetTok()    - Get token
  905. X*    GetTokNC()    - Get token but skip comment
  906. X*    UnGetTok()    - Unget token
  907. X*    OpenTok()    - Open file to read tokens from
  908. X* Revision:
  909. X*    Ver    Date   By        Reason
  910. X*    ---    ----   --        ------
  911. X*    1.00   900619 Lars Berntzon    Created
  912. X******************************************************************************/
  913. X#include "config.h"
  914. X#include <stdio.h>
  915. X#include <ctype.h>
  916. X#include <string.h>
  917. X#ifdef STDLIB_H
  918. X#include <stdlib.h>
  919. X#endif
  920. X#ifdef MALLOC_H
  921. X#include <malloc.h>
  922. X#endif
  923. X#include "token.h"
  924. X#define isnormal(c) (isalnum(c) || (c) == '_')
  925. X    /* G l o b a l   v a r i a b l e s */
  926. Xint newline = 1;       /* Number of newlines before this token    */
  927. Xint line = 1;           /* Current line number            */
  928. XFILE *in;           /* The input file pointer            */
  929. X    /* L o c a l   v a r i a b l e */
  930. Xstatic struct saved {       /* Queue of ungotten tokens            */
  931. X    struct saved *next;
  932. X    char token[TOKENSIZE];
  933. X} *saved = NULL;
  934. Xtypedef void *(*state_t)(char *);
  935. X/*******************************************************************************
  936. X *        G E T O K 
  937. X *        ---------
  938. X * Description:
  939. X *    Reads one token from input file (or from ungotten token).
  940. X * Output:
  941. X *    str    - String where data wil be put (if not NULL).
  942. X * Return:
  943. X *    String containing token, NULL if end of file.
  944. X ******************************************************************************/
  945. Xchar *GetTok(char *str)
  946. X    static char token[TOKENSIZE];
  947. X    static int ch = ' ';
  948. X    struct saved *p;
  949. X    int pos;
  950. X    enum { gt_init, gt_got_delim, gt_normal,
  951. X           gt_searching_quote, gt_got_backslash } state = gt_init;
  952. X    if (p = saved) {
  953. X    strncpy(token, saved->token, TOKENSIZE);
  954. X    saved = p->next;
  955. X    free(p);
  956. X    pos = 1;
  957. X    goto found;
  958. X    }
  959. X    
  960. X    token[0] = 0;
  961. X    
  962. X    newline = 0;
  963. X    
  964. X    if (ch == EOF) return NULL;
  965. X    
  966. X    for(pos = 0; ch != EOF; ch = getc(in)) {
  967. X    if (ch == '\n') {
  968. X        line++;
  969. X        newline++;
  970. X    switch(state) 
  971. X    case gt_init:
  972. X        if (isspace(ch)) {
  973. X            break;
  974. X        }
  975. X        else if (ch == '"') {
  976. X        token[pos++] = ch;
  977. X        state = gt_searching_quote;
  978. X        }
  979. X        else if (!isnormal(ch)) {
  980. X        token[pos++] = ch;
  981. X        token[pos++] = 0;
  982. X        ch = ' ';
  983. X        goto found;
  984. X        }
  985. X        else if (isnormal(ch)) {
  986. X            token[pos++] = ch;
  987. X            state = gt_normal;
  988. X        }
  989. X        break;
  990. X    case gt_normal:
  991. X        if (isnormal(ch)) {
  992. X            token[pos++] = ch;
  993. X        }
  994. X        else {
  995. X        token[pos++] = 0;
  996. X        goto found;
  997. X        }
  998. X        break;
  999. X    case gt_searching_quote:
  1000. X        token[pos++] = ch;
  1001. X        if (ch == '\\') {
  1002. X            state = gt_got_backslash;
  1003. X        }
  1004. X        else {
  1005. X            if (ch == '"') {
  1006. X                token[pos++] = 0;
  1007. X                ch = ' ';
  1008. X                goto found;
  1009. X            }
  1010. X        }
  1011. X        break;
  1012. X    case gt_got_backslash:
  1013. X        token[pos++] = ch;
  1014. X        state = gt_searching_quote;
  1015. X        break;
  1016. X    }
  1017. Xfound:
  1018. X    if (pos == 0) return NULL;
  1019. X    if (str) return strcpy(str, token);
  1020. X    return token;
  1021. X/*******************************************************************************
  1022. X *        G E T T O K N C
  1023. X *        ---------------
  1024. X * Description:
  1025. X *    Reads one token from input file (or from ungotten token) and skips
  1026. X *    C-style comments.
  1027. X * Output:
  1028. X *    str    - String where data will be put (if not NULL).
  1029. X * Return:
  1030. X *    String containing token, NULL if EOF.
  1031. X ******************************************************************************/
  1032. Xstatic void *nc_init(char *);
  1033. Xstatic void *nc_found_leading_slash(char *);
  1034. Xstatic void *nc_searching_star(char *);
  1035. Xstatic void *nc_expect_slash(char *);
  1036. Xchar *GetTokNC(char *token)
  1037. X    char *ret;
  1038. X    state_t state = nc_init;
  1039. X    while((ret = GetTok(token)) != NULL &&
  1040. X          (state = (state_t) (*state)(ret)) != NULL) {
  1041. X    }
  1042. X    return ret;
  1043. Xstatic void *nc_init(char *token)
  1044. X    if(strcmp(token, "/") != 0) return NULL;
  1045. X    return (void *)nc_found_leading_slash;
  1046. Xstatic void *nc_found_leading_slash(char *token)
  1047. X    if(strcmp(token, "*") == 0) return (void *)nc_searching_star;
  1048. X    UnGetTok(token);
  1049. X    strcpy(token, "/");
  1050. X    return NULL;
  1051. Xstatic void *nc_searching_star(char *token)
  1052. X    if(strcmp(token, "*") == 0) return (void *)nc_expect_slash;
  1053. X    return (void *)nc_searching_star;
  1054. Xstatic void *nc_expect_slash(char *token)
  1055. X    if (strcmp(token, "/") == 0) return (void *)nc_init;
  1056. X    UnGetTok(token);
  1057. X    return (void *)nc_searching_star;
  1058. X/*******************************************************************************
  1059. X *        U N G E T T O K
  1060. X *        ---------------
  1061. X * Description:
  1062. X *    Returns a token to be read later by GetTok().
  1063. X * Input:
  1064. X *    str    - String to be put back.
  1065. X ******************************************************************************/
  1066. Xvoid
  1067. XUnGetTok(char *str)
  1068. X    struct saved *p = NULL;
  1069. X    
  1070. X    if ((p = (struct saved *)malloc(sizeof *p)) == NULL) {
  1071. X    fprintf(stderr, "Out of memory");
  1072. X    return;
  1073. X    }
  1074. X    p->next = saved;
  1075. X    saved = p;
  1076. X    strncpy(saved->token, str, TOKENSIZE);
  1077. X/*******************************************************************************
  1078. X *        O P E N T O K
  1079. X *        -------------
  1080. X * Description:
  1081. X *    Open a file to read tokens from.
  1082. X * Input:
  1083. X *    name    - Name of file.
  1084. X * Return:
  1085. X *    Opened files pointer, of NULL if failure.
  1086. X ******************************************************************************/
  1087. XFILE *OpenTok(char *name)
  1088. X    if (in != NULL) {
  1089. X    fclose(in);
  1090. X    }
  1091. X    return in = fopen(name, "r");
  1092. X#ifdef STANDALONE
  1093. X/*******************************************************************************
  1094. X *        M A I N
  1095. X *        -------
  1096. X * Description:
  1097. X *    Main routine when compiled as standalone.
  1098. X *    This is only used for test.
  1099. X ******************************************************************************/
  1100. Xmain()
  1101. X    char filename[100];
  1102. X    char *p;
  1103. X    
  1104. X    printf("Enter filename of 'stdin': ");
  1105. X    scanf("%s", filename);
  1106. X    if (strcmp(filename, "stdin") == 0) {
  1107. X    printf("Using stdin\n");
  1108. X    in = stdin;
  1109. X    }
  1110. X    else if (OpenTok(filename) == NULL) {
  1111. X    fprintf(stderr, "Can't open file '%s'\n", filename);
  1112. X    exit(1);
  1113. X    }
  1114. X    while(p = GetTokNC(NULL)) printf("'%s'\n", p);
  1115. X    UnGetTok("ungotten 1");
  1116. X    while(p = GetTokNC(NULL)) printf("'%s'\n", p);
  1117. X    UnGetTok("ungotten 2");
  1118. X    UnGetTok("ungotten 3");
  1119. X    while(p = GetTokNC(NULL)) printf("'%s'\n", p);
  1120. X    printf("END\n");    
  1121. X#endif /* STANDALONE */
  1122. END_OF_FILE
  1123. if test 6503 -ne `wc -c <'src/token.c'`; then
  1124.     echo shar: \"'src/token.c'\" unpacked with wrong size!
  1125. # end of 'src/token.c'
  1126. echo shar: End of archive 2 \(of 3\).
  1127. cp /dev/null ark2isdone
  1128. MISSING=""
  1129. for I in 1 2 3 ; do
  1130.     if test ! -f ark${I}isdone ; then
  1131.     MISSING="${MISSING} ${I}"
  1132.     fi
  1133. if test "${MISSING}" = "" ; then
  1134.     echo You have unpacked all 3 archives.
  1135.     rm -f ark[1-9]isdone
  1136.     echo You still need to unpack the following archives:
  1137.     echo "        " ${MISSING}
  1138. ##  End of shell archive.
  1139. exit 0
  1140.