home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume27 / conv123 / part02 < prev    next >
Encoding:
Text File  |  1993-09-05  |  65.4 KB  |  2,227 lines

  1. Newsgroups: comp.sources.unix
  2. From: greg@brooktree.com (Gregory Santos)
  3. Subject: v27i032: conv123 - convert ASCII files to Lotus-123 format, Part02/02
  4. References: <1.747292168.20241@gw.home.vix.com>
  5. Sender: unix-sources-moderator@gw.home.vix.com
  6. Approved: vixie@gw.home.vix.com
  7.  
  8. Submitted-By: greg@brooktree.com (Gregory Santos)
  9. Posting-Number: Volume 27, Issue 32
  10. Archive-Name: conv123/part02
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line, then unpack
  14. # it by saving it into a file and typing "sh file".  To overwrite existing
  15. # files, type "sh file -c".  You can also feed this as standard input via
  16. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  17. # will see the following message at the end:
  18. #        "End of archive 2 (of 2)."
  19. # Contents:  conv123.c grph123.c
  20. # Wrapped by vixie@gw.home.vix.com on Sun Sep  5 22:08:57 1993
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'conv123.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'conv123.c'\"
  24. else
  25. echo shar: Extracting \"'conv123.c'\" \(33229 characters\)
  26. sed "s/^X//" >'conv123.c' <<'END_OF_FILE'
  27. X#include <stdio.h>
  28. X#include <fcntl.h>
  29. X#include <string.h>
  30. X#include <stdlib.h>
  31. X
  32. X#include "lotus.h"
  33. X#include "swapb.h"
  34. X
  35. X
  36. X#define MAXHEADLINES 2    /* number of header lines allowed above dash line */
  37. X#define MAXROWS 8192    /* max rows, dependent on 12-bit maximum value */
  38. X#define MAXCOLS 124    /* maximum number of columns in the spreadsheet */
  39. X#define MAXCOLWD 36    /* maximum column width */
  40. X#define MAXINRECLEN (MAXCOLS * MAXCOLWD + 5 * MAXCOLS)
  41. X#define COLEXTEND 1    /* makes cell this much bigger than definition */
  42. X
  43. Xvoid int2s();        /* routine to stuff int bits into char representation */
  44. X
  45. XFILE *infile, *outfile;
  46. X
  47. Xshort current_row;    /* input file record */
  48. Xlong current_offset;    /* output file offset */
  49. X
  50. Xshort col_width[MAXCOLS], col_pos[MAXCOLS], col_type[MAXCOLS];
  51. Xshort formula_start_row[MAXCOLS], formula_end_row[MAXCOLS];
  52. Xshort formula_start_col, formula_end_col;
  53. Xshort decimals(), dec_pl, col_dec_pl[MAXCOLS], row_dec_pl;
  54. X
  55. X/***********************************/
  56. X/* declare lotus record structures */
  57. X/***********************************/
  58. X
  59. XBOF BOFr;
  60. X
  61. XRANGE RANGEr;
  62. XCALCCOUNT CALCCOUNTr;
  63. XCALCMODE CALCMODEr;
  64. XCALCORDER CALCORDERr;
  65. XSPLIT SPLITr;
  66. XSYNC SYNCr;
  67. XWINDOW1 WINDOW1r;
  68. XCOLW1 COLW1r;
  69. XTABLE TABLEr;
  70. XQRANGE QRANGEr;
  71. XPRANGE PRANGEr;
  72. XLABEL LABELr;
  73. X/*  INTEGER INTEGERr; */
  74. XNUMBER NUMBERr;
  75. XFORMULA FORMULAr;    
  76. XLEOF LEOFr;
  77. X
  78. X
  79. X
  80. Xmain(argc,argv)
  81. Xint argc;
  82. Xchar *argv[];
  83. X{
  84. X
  85. X/**********************/
  86. X/* main declarations  */
  87. X/**********************/
  88. X
  89. X    int fstat;
  90. X    char *p, *bp, *fp, *sstat;
  91. X    char headerbuf[MAXHEADLINES + 1][MAXINRECLEN + 1];
  92. X    char inbuf[MAXINRECLEN + 1], util_buf[256];
  93. X    char infilename[96];
  94. X    char outfilename[96];
  95. X    char blank_buf[80];
  96. X
  97. X    int i, j, l, debug, fs, us;
  98. X
  99. X    unsigned short i1, j1, l1;
  100. X
  101. X    short number_of_cols, header_lines;
  102. X
  103. X    double dbl_value;
  104. X
  105. X    long RANGE_offset;
  106. X
  107. X/**************************************/
  108. X/* initialize lotus record structures */
  109. X/**************************************/
  110. X
  111. X    int2s(swapb(BOF_op),BOFr.opcode);
  112. X    int2s(swapb(BOF_len),BOFr.record_length);
  113. X    int2s(swapb((unsigned short)1030),BOFr.ff_version);
  114. X
  115. X    int2s(swapb(RANGE_op),RANGEr.opcode);
  116. X    int2s(swapb(RANGE_len),RANGEr.record_length);
  117. X    int2s(swapb((unsigned short)0),RANGEr.start_column);
  118. X    int2s(swapb((unsigned short)0),RANGEr.start_row);
  119. X    int2s(swapb((unsigned short)0),RANGEr.end_column);
  120. X    int2s(swapb((unsigned short)0),RANGEr.end_row);
  121. X
  122. X    int2s(swapb(CALCCOUNT_op),CALCCOUNTr.opcode);
  123. X    int2s(swapb(CALCCOUNT_len),CALCCOUNTr.record_length);
  124. X    *CALCCOUNTr.iteration_count = 1;
  125. X
  126. X    int2s(swapb(CALCMODE_op),CALCMODEr.opcode);
  127. X    int2s(swapb(CALCMODE_len),CALCMODEr.record_length);
  128. X    *CALCMODEr.recalculation = 0xFF;    /* automatic recalc */
  129. X
  130. X    int2s(swapb(CALCORDER_op),CALCORDERr.opcode);
  131. X    int2s(swapb(CALCORDER_len),CALCORDERr.record_length);
  132. X    *CALCORDERr.calc_order = 0x00;    /* natural order */
  133. X
  134. X    int2s(swapb(SPLIT_op),SPLITr.opcode);
  135. X    int2s(swapb(SPLIT_len),SPLITr.record_length);
  136. X    *SPLITr.window_split = 0x00;    /* no window split */
  137. X
  138. X    int2s(swapb(SYNC_op),SYNCr.opcode);
  139. X    int2s(swapb(SYNC_len),SYNCr.record_length);
  140. X    *SYNCr.window_sync = 0xFF;        /* window synchronized */
  141. X
  142. X    int2s(swapb(WINDOW1_op),WINDOW1r.opcode);
  143. X    int2s(swapb(WINDOW1_len),WINDOW1r.record_length);
  144. X    int2s(swapb((unsigned short)0),WINDOW1r.cc_column);
  145. X    int2s(swapb((unsigned short)0),WINDOW1r.cc_row);
  146. X    *WINDOW1r.cell_format = 2;    /* two decimal places */
  147. X    *WINDOW1r.unused1 = 0;
  148. X    int2s(swapb((unsigned short)9),WINDOW1r.column_width);
  149. X    int2s(swapb((unsigned short)8),WINDOW1r.ncol_on_screen);
  150. X    int2s(swapb((unsigned short)20),WINDOW1r.nrow_on_screen);
  151. X    int2s(swapb((unsigned short)0),WINDOW1r.leftmost_column);
  152. X    int2s(swapb((unsigned short)0),WINDOW1r.top_row);
  153. X    int2s(swapb((unsigned short)0),WINDOW1r.ntitle_col);
  154. X    int2s(swapb((unsigned short)0),WINDOW1r.ntitle_row);
  155. X    int2s(swapb((unsigned short)0),WINDOW1r.ltitle_col);
  156. X    int2s(swapb((unsigned short)0),WINDOW1r.ttitle_row);
  157. X    int2s(swapb((unsigned short)4),WINDOW1r.borderwd_col);
  158. X    int2s(swapb((unsigned short)4),WINDOW1r.borderwd_row);
  159. X    int2s(swapb((unsigned short)72),WINDOW1r.window_width);
  160. X    *WINDOW1r.unused2 = 0;
  161. X    *WINDOW1r.unused3 = 0;
  162. X
  163. X    /* there are multiple of these, so just init basic elements for now */
  164. X    int2s(swapb(COLW1_op),COLW1r.opcode);
  165. X    int2s(swapb(COLW1_len),COLW1r.record_length);
  166. X
  167. X
  168. X    int2s(swapb(TABLE_op),TABLEr.opcode);
  169. X    int2s(swapb(TABLE_len),TABLEr.record_length);
  170. X    *TABLEr.table_ind = 0x00;        /* no table */
  171. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.table_start_column);
  172. X    int2s(swapb((unsigned short)0),TABLEr.table_start_row);
  173. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.table_end_column);
  174. X    int2s(swapb((unsigned short)0),TABLEr.table_end_row);
  175. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.cell1_start_column);
  176. X    int2s(swapb((unsigned short)0),TABLEr.cell1_start_row);
  177. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.cell1_end_column);
  178. X    int2s(swapb((unsigned short)0),TABLEr.cell1_end_row);
  179. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.cell2_start_column);
  180. X    int2s(swapb((unsigned short)0),TABLEr.cell2_start_row);
  181. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.cell2_end_column);
  182. X    int2s(swapb((unsigned short)0),TABLEr.cell2_end_row);
  183. X
  184. X
  185. X    int2s(swapb(QRANGE_op),QRANGEr.opcode);
  186. X    int2s(swapb(QRANGE_len),QRANGEr.record_length);
  187. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.input_start_column);
  188. X    int2s(swapb((unsigned short)0),QRANGEr.input_start_row);
  189. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.input_end_column);
  190. X    int2s(swapb((unsigned short)0),QRANGEr.input_end_row);
  191. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.output_start_column);
  192. X    int2s(swapb((unsigned short)0),QRANGEr.output_start_row);
  193. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.output_end_column);
  194. X    int2s(swapb((unsigned short)0),QRANGEr.output_end_row);
  195. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.criteria_start_column);
  196. X    int2s(swapb((unsigned short)0),QRANGEr.criteria_start_row);
  197. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.criteria_end_column);
  198. X    int2s(swapb((unsigned short)0),QRANGEr.criteria_end_row);
  199. X    *QRANGEr.command = 0;        /* no command */
  200. X
  201. X    int2s(swapb(PRANGE_op),PRANGEr.opcode);
  202. X    int2s(swapb(PRANGE_len),PRANGEr.record_length);
  203. X    int2s(swapb((unsigned short)0xFFFF),PRANGEr.start_column);
  204. X    int2s(swapb((unsigned short)0),PRANGEr.start_row);
  205. X    int2s(swapb((unsigned short)0xFFFF),PRANGEr.end_column);
  206. X    int2s(swapb((unsigned short)0),PRANGEr.end_row);
  207. X
  208. X    int2s(swapb(LABEL_op),LABELr.opcode);
  209. X    *LABELr.format = 0xFF;    /* lotus default */
  210. X    *LABELr.position = 0x27;    /* single quote ('), left justified */
  211. X
  212. X
  213. X    int2s(swapb(NUMBER_op),NUMBERr.opcode);
  214. X    int2s(swapb(NUMBER_len),NUMBERr.record_length);
  215. X    *NUMBERr.format = 0xFF;    /* lotus default */
  216. X
  217. X    int2s(swapb(FORMULA_op),FORMULAr.opcode);
  218. X    *FORMULAr.format = 0xFF;    /* lotus default */
  219. X    
  220. X
  221. X    int2s(swapb(LEOF_op),LEOFr.opcode);
  222. X    int2s(swapb(LEOF_len),LEOFr.record_length);
  223. X
  224. X/************************************/
  225. X/* Now some ordinary initialization */
  226. X/************************************/
  227. X
  228. X    current_offset = 0L;
  229. X    current_row = -1;
  230. X
  231. X/*******************************/
  232. X/* assign files                */
  233. X/*******************************/
  234. X
  235. X    infile = stdin;        /* typical input is stdin */
  236. X    outfile = stdout;        /* typical output is stdout */
  237. X
  238. X    debug = 0;            /* don't do it */
  239. X
  240. X/* Make sure blank_buf is initialized */
  241. X
  242. X    for (i = 0; i < 80; i++)
  243. X    blank_buf[i] = ' ';
  244. X
  245. X/************************************/
  246. X/* if there are input parameters,   */
  247. X/* deal with them.                  */
  248. X/************************************/
  249. X
  250. X    if (argc > 3) {
  251. X     fprintf(stderr,"Allowed parameters are input and output filenames.\n");
  252. X    return(1);
  253. X    }
  254. X
  255. X/* open main data input file as a stream (maybe) */
  256. X    if (argc > 1) {
  257. X        fclose(infile);
  258. X    strcpy(infilename,argv[1]);
  259. X    if ((infile = fopen(infilename,"r")) == NULL) {
  260. X        fprintf(stderr,"Open of input data file %s failed.\n",infilename);
  261. X        return(1);
  262. X    }
  263. X    }
  264. X
  265. X/* create and open output file directly (maybe) */
  266. X    if (argc > 2) {
  267. X        fclose(outfile);
  268. X    strcpy(outfilename,argv[2]);
  269. X    if ((outfile = fopen(outfilename,"w+")) == NULL) {
  270. X        fprintf(stderr,"open of output data file %s failed.\n",outfilename);
  271. X        fclose(infile);
  272. X        return;
  273. X    }
  274. X    }
  275. X
  276. X/************************************/
  277. X/* now get to work translating it   */
  278. X/************************************/
  279. X
  280. X    if (get_header_info(headerbuf,&number_of_cols,&header_lines))
  281. X    return(1);
  282. X
  283. X#ifdef DEBUG
  284. X    for (i = 0; i < number_of_cols; i++)
  285. X    fprintf(stderr,"%d %d %d %d\n",i,col_width[i],col_type[i],col_pos[i]);
  286. X    fprintf(stderr,"total columns: %d header lines: %d\n",number_of_cols,header_lines);
  287. X#endif
  288. X
  289. X/************************************/
  290. X/* we've got SOMETHING, so go ahead */
  291. X/* and start the 123 output!        */
  292. X/************************************/
  293. X
  294. X    p = (char *)(&BOFr);
  295. X    fs = output_lotus_record(p);
  296. X
  297. X#ifdef DEBUG
  298. X    fprintf(stderr,"Offset after BOF: %d\n",current_offset);
  299. X#endif
  300. X
  301. X/** might as well set the number of columns now, since we know it **/
  302. X    RANGE_offset = current_offset;
  303. X    int2s(swapb((unsigned short)(number_of_cols - 1)),RANGEr.end_column);
  304. X    p = (char *)(&RANGEr);
  305. X    output_lotus_record(p);
  306. X
  307. X#ifdef DEBUG
  308. X    fprintf(stderr,"Offset after RANGE: %d\n",current_offset);
  309. X#endif
  310. X
  311. X/************************************/
  312. X/* and how about the column widths  */
  313. X/************************************/
  314. X
  315. X    p = (char *)(&COLW1r);
  316. X    for (j = 0; j < number_of_cols; j++) {
  317. X    int2s(swapb(j),COLW1r.column_number);
  318. X    j1 = col_width[j] + COLEXTEND;
  319. X    int2s(swapb(j1),COLW1r.column_width);
  320. X    output_lotus_record(p);
  321. X    }
  322. X
  323. X#ifdef DEBUG
  324. X    fprintf(stderr,"Column width records added...\n");
  325. X#endif
  326. X
  327. X/**********************************/
  328. X/* create header labels, if there */
  329. X/*  are any to create             */
  330. X/**********************************/
  331. X
  332. X    if (header_lines) {
  333. X    p = (char *)(&LABELr);
  334. X
  335. X    current_row = -1;
  336. X    for (i = 0; i <= header_lines; i++) {
  337. X        current_row++;
  338. X        for (j = 0; j < number_of_cols; j++) {
  339. X            int2s(swapb(j),LABELr.column);
  340. X            int2s(swapb((unsigned short)current_row),LABELr.row);
  341. X            *LABELr.string = '\0';
  342. X            strncat(LABELr.string,(headerbuf[i] + col_pos[j]),col_width[j]);
  343. X            int2s(swapb((unsigned short)(strlen(LABELr.string) + 7)),
  344. X                LABELr.record_length);
  345. X            output_lotus_record(p);
  346. X        }
  347. X
  348. X    }
  349. X    }
  350. X
  351. X#ifdef DEBUG
  352. X    fprintf(stderr,"Offset after LABELS: %d\n",current_offset);
  353. X#endif
  354. X
  355. X/* end of header processing */
  356. X
  357. X/*******************************/
  358. X/* process remaining lines     */
  359. X/*******************************/
  360. X
  361. X
  362. X    while ((fs = getline(inbuf,MAXINRECLEN,infile)) != EOF) {
  363. X
  364. X    formula_start_col = -1;        /* start out pessimistic */
  365. X    formula_end_col = -1;
  366. X    row_dec_pl = 0;
  367. X
  368. X    for (j = 0; j < number_of_cols; j++) {
  369. X      if (col_pos[j] < fs) {    /* get paranoid about short lines */
  370. X        *util_buf = '\0';
  371. X        strncat(util_buf,(inbuf + col_pos[j]),col_width[j]);
  372. X        us = trim(util_buf);
  373. X        if (us > 0) {
  374. X        if (sscanf(util_buf," %lf%n",&dbl_value,&l) && (us == l)) {
  375. X#ifdef DEBUG
  376. X          fprintf(stderr,"%d %d %s|\n",us,l,util_buf);
  377. X#endif
  378. X        /*** just a number; keep track of start/end values ***/
  379. X        if (formula_start_row[j] < 0)
  380. X            formula_start_row[j] = current_row;
  381. X        formula_end_row[j] = current_row;
  382. X        if (formula_start_col < 0)
  383. X            formula_start_col = j;
  384. X        formula_end_col = j;
  385. X
  386. X        if ((dec_pl = decimals(util_buf)) > col_dec_pl[j])
  387. X            col_dec_pl[j] = dec_pl;
  388. X        if (dec_pl > row_dec_pl)
  389. X            row_dec_pl = dec_pl;
  390. X
  391. X        p = (char *)(&NUMBERr);
  392. X
  393. X        *NUMBERr.format = (char)(0x80 + dec_pl);
  394. X        int2s(swapb(j),NUMBERr.column);
  395. X        int2s(swapb((unsigned short)current_row),NUMBERr.row);
  396. X        stdbl(dbl_value,NUMBERr.value);
  397. X        output_lotus_record(p);
  398. X
  399. X        } else if (*util_buf == '@') {  /* test for formula */
  400. X        if (fstat = create_formula_record(util_buf,j)) {
  401. X            fprintf(stderr,"Bad formula at line %d, error %d\n",current_row,fstat);
  402. X            return(1);
  403. X        }
  404. X        if (!strcmp(util_buf,"@NUL")) {    /* it's a placeholder */
  405. X            if (formula_start_row[j] < 0)
  406. X            formula_start_row[j] = current_row;
  407. X            formula_end_row[j] = current_row;
  408. X            if (formula_start_col < 0)
  409. X            formula_start_col = j;
  410. X            formula_end_col = j;
  411. X        }
  412. X            
  413. X          } else {        /* OK, so it's just a plain-old string  */
  414. X                /* check for string override characters */
  415. X        if (us > 1 && (*util_buf == '\'' || *util_buf == '"')) {
  416. X            *LABELr.position = *util_buf;
  417. X            *util_buf = ' ';
  418. X            us = trim(util_buf);
  419. X        }
  420. X        p = (char *)(&LABELr);
  421. X        col_type[j] = 0;    /* non_numeric column */
  422. X        formula_start_row[j] = formula_end_row[j] = -1;
  423. X        formula_start_col = formula_end_col = -1;
  424. X        col_dec_pl[j] = row_dec_pl = 0;
  425. X        int2s(swapb(j),LABELr.column);
  426. X        int2s(swapb((unsigned short)current_row),LABELr.row);
  427. X        strcpy(LABELr.string,util_buf);
  428. X        int2s(swapb((unsigned short)(strlen(LABELr.string) + 7)),
  429. X                LABELr.record_length);
  430. X        output_lotus_record(p);
  431. X        *LABELr.position = 0x27; /* single quote, left-justified */
  432. X        }
  433. X      }
  434. X     }
  435. X    }
  436. X    }
  437. X
  438. X
  439. X/*********************/
  440. X/* end of lotus file */
  441. X/*********************/
  442. X
  443. X    p = (char *)(&LEOFr);
  444. X    output_lotus_record(p);
  445. X
  446. X}
  447. X
  448. X/*****************************************/
  449. X/* scan input record for column widths   */
  450. X/* and return values                     */
  451. X/*****************************************/
  452. X
  453. Xint
  454. Xget_header_info(bufp,cols,hlines)
  455. Xchar bufp[][MAXINRECLEN + 1];
  456. Xshort *cols, *hlines;
  457. X{
  458. X    int  i, j, count = -1;
  459. X    char c;
  460. X
  461. X    for (i = 0; i < MAXHEADLINES; i++)
  462. X    bufp[i][0] = '\0';
  463. X    *hlines = -1;
  464. X
  465. X    do {
  466. X    if (++(*hlines) > MAXHEADLINES || !getline(bufp[*hlines],MAXINRECLEN,infile)) {
  467. X        fprintf(stderr,"Could not locate column definition within %d lines in input file.\n",MAXHEADLINES);
  468. X        return(1);
  469. X    }
  470. X    } while (bufp[*hlines][0] != '-');
  471. X
  472. X/*** now find out the number of columns and their widths ***/
  473. X
  474. X    count = j = 0;
  475. X    while (bufp[*hlines][j]) {
  476. X    i = 0;
  477. X    while (bufp[*hlines][j + i] == '-') {
  478. X        i++;
  479. X    }
  480. X    col_width[count] = i;
  481. X    col_pos[count] = j;
  482. X    col_type[count] = 1;        /* just initialization */
  483. X    formula_start_row[count] = -1;    /* just initialization */
  484. X    formula_end_row[count] = -1;    /* just initialization */
  485. X    col_dec_pl[count] = 0;        /* just initialization */
  486. X    count++;
  487. X    j += i;
  488. X    while (bufp[*hlines][j] && (bufp[*hlines][j] != '-')) {
  489. X        j++;
  490. X    }
  491. X    }
  492. X    *cols = count;
  493. X
  494. X    return(0);
  495. X}
  496. X
  497. X/*************************************************/
  498. X/* create a lotus formula - uses a couple of     */
  499. X/* other routines, returns zero if successful    */
  500. X/*************************************************/
  501. X
  502. Xint
  503. Xcreate_formula_record(formbuf,c_col)
  504. Xchar *formbuf;
  505. Xshort c_col;    /* current column; current row is global (Emerson) */
  506. X{
  507. X    short dec_pl, s_col, s_row, e_col, e_row;
  508. X    short s2_col, s2_row, e2_col, e2_row;
  509. X    short rvalue, bfunction = 0;
  510. X    char *bp, util_buf[256];
  511. X    char *bnamebuf = "+-*/%";
  512. X    int ichar;
  513. X
  514. X/****************************************************/
  515. X/* If formbuf is a binary function, normalize the   */
  516. X/* formula buffer -- ranges are already normalized, */
  517. X/* so just copy                                     */
  518. X/****************************************************/
  519. X
  520. X    bp = util_buf;
  521. X    *bp = '\0';
  522. X    if (strchr(bnamebuf,*(formbuf + 2)) != NULL) { /* binary function */
  523. X    bfunction++;
  524. X    strncat(bp,formbuf,3);
  525. X    strcat(bp,"  ");
  526. X    strcat(bp,(formbuf + 3));
  527. X    } else
  528. X    strcat(bp,formbuf);
  529. X
  530. X/* now for any trailing number */
  531. X
  532. X    rvalue = atoi(bp + 5) - 1;
  533. X#ifdef DEBUG
  534. X  fprintf(stderr,"range override value: %d\n",rvalue);
  535. X#endif
  536. X
  537. X/****************************************/
  538. X/* Figure out if all the ranges are     */
  539. X/* valid in their context, i.e.,        */
  540. X/* column-wise or row-wise; then do it, */
  541. X/* then reset.                          */
  542. X/****************************************/
  543. X
  544. X    ichar = *(++bp);
  545. X    switch (ichar) {
  546. X
  547. X    case 'B':        /* column-wise + one row value formula; uses   */
  548. X            /* default ranges for column, override for row */
  549. X
  550. X/***********/
  551. X/* R stuff -- determine start and end columns; row is known */
  552. X/***********/
  553. X
  554. X    s2_row = current_row;
  555. X    e2_row = current_row;
  556. X
  557. X/*************************************************/
  558. X/* decide whether to override the default start  */
  559. X/* column; note: decimal places are not affected */
  560. X/*************************************************/
  561. X
  562. X    s2_col = formula_start_col;    /* start out optimistic */
  563. X
  564. X/* if it's a binary function, back up one step for start */
  565. X
  566. X    if (bfunction)
  567. X        s2_col = formula_end_col - 1;
  568. X
  569. X/* if there's an override, try to use it */
  570. X
  571. X    if ((rvalue > -1) && (rvalue <= formula_end_col))
  572. X        s2_col = rvalue;
  573. X    else
  574. X        rvalue = -1;
  575. X
  576. X/* if all has failed, just use current location for start AND end */
  577. X
  578. X    if (s2_col < 0) {
  579. X        s2_col = c_col;
  580. X        e2_col = c_col;
  581. X    } else
  582. X    e2_col = formula_end_col;
  583. X
  584. X/***********/
  585. X/* C stuff -- determine start and end rows; column is known */
  586. X/***********/
  587. X
  588. X    if ((s_row = formula_start_row[c_col]) < 0) {
  589. X        s_row = current_row;
  590. X        e_row = current_row;
  591. X    } else
  592. X        e_row = formula_end_row[c_col];
  593. X
  594. X/* B stuff -- number of decimal places */
  595. X
  596. X    dec_pl = (row_dec_pl > col_dec_pl[c_col]) ? row_dec_pl : col_dec_pl[c_col];
  597. X
  598. X    if (create_lotus_multiple(bp,dec_pl,c_col,c_col,s_row,c_col,e_row,s2_col,s2_row,e2_col,e2_row,rvalue))
  599. X        return(3);
  600. X
  601. X    /* reset default row range and dec, set default column range, end */
  602. X    formula_start_col = -1;
  603. X    formula_end_col = -1;
  604. X    row_dec_pl = 0;
  605. X
  606. X    if (formula_start_row[c_col] < 0)
  607. X        formula_start_row[c_col] = current_row;
  608. X    formula_end_row[c_col] = current_row;
  609. X    if (dec_pl > col_dec_pl[c_col])
  610. X        col_dec_pl[c_col] = dec_pl;
  611. X
  612. X    /* reset default column range and dec, set row default range, end */
  613. X    formula_start_row[c_col] = -1;
  614. X    formula_end_row[c_col] = -1;
  615. X    col_dec_pl[c_col] = 0;
  616. X
  617. X    if (formula_start_col < 0)
  618. X        formula_start_col = c_col;
  619. X    formula_end_col = c_col;
  620. X    if (dec_pl > row_dec_pl)
  621. X        row_dec_pl = dec_pl;
  622. X
  623. X    break;
  624. X
  625. X    case 'C':        /* column-wise formulae; just uses default ranges */
  626. X
  627. X    dec_pl = col_dec_pl[c_col];
  628. X
  629. X    if ((s_row = formula_start_row[c_col]) < 0) {
  630. X        s_row = current_row;
  631. X        e_row = current_row;
  632. X    } else
  633. X        e_row = formula_end_row[c_col];
  634. X
  635. X    /* if it's a binary function, force the back up one step */
  636. X    if (bfunction && (current_row > 2)) {
  637. X      s_row = current_row - 2;
  638. X      e_row = current_row - 1;
  639. X    }
  640. X
  641. X    if (create_lotus_formula(bp,dec_pl,c_col,c_col,s_row,c_col,e_row,rvalue))
  642. X        return(3);
  643. X
  644. X    /* reset default column range and dec, set row default range, end */
  645. X    formula_start_row[c_col] = -1;
  646. X    formula_end_row[c_col] = -1;
  647. X    col_dec_pl[c_col] = 0;
  648. X
  649. X    if (formula_start_col < 0)
  650. X        formula_start_col = c_col;
  651. X    formula_end_col = c_col;
  652. X    if (dec_pl > row_dec_pl)
  653. X        row_dec_pl = dec_pl;
  654. X
  655. X    break;
  656. X
  657. X    case 'R':        /* row-wise formula - check also for specified range */
  658. X
  659. X    s_row = current_row;
  660. X    e_row = current_row;
  661. X    dec_pl = row_dec_pl;
  662. X
  663. X/*************************************************/
  664. X/* decide whether to override the default start  */
  665. X/* column; note: decimal places are not affected */
  666. X/*************************************************/
  667. X
  668. X    s_col = formula_start_col;    /* start out optimistic */
  669. X
  670. X/* if it's a binary function, back up one step for start */
  671. X
  672. X    if (bfunction)
  673. X        s_col = formula_end_col - 1;
  674. X
  675. X/* if there's an override, try to use it */
  676. X
  677. X    if ((rvalue > -1) && (rvalue <= formula_end_col))
  678. X        s_col = rvalue;
  679. X    else
  680. X        rvalue = -1;
  681. X
  682. X/* if all has failed, just use current location for start AND end */
  683. X
  684. X    if (s_col < 0) {
  685. X        s_col = c_col;
  686. X        e_col = c_col;
  687. X    } else
  688. X    e_col = formula_end_col;
  689. X
  690. X    if (create_lotus_formula(bp,dec_pl,c_col,s_col,s_row,e_col,e_row,rvalue))
  691. X        return(3);
  692. X
  693. X    /* reset default row range and dec, set default column range, end */
  694. X    formula_start_col = -1;
  695. X    formula_end_col = -1;
  696. X    row_dec_pl = 0;
  697. X
  698. X    if (formula_start_row[c_col] < 0)
  699. X        formula_start_row[c_col] = current_row;
  700. X    formula_end_row[c_col] = current_row;
  701. X    if (dec_pl > col_dec_pl[c_col])
  702. X        col_dec_pl[c_col] = dec_pl;
  703. X    break;
  704. X
  705. X    case 'N':        /* null function; just return, increment counters */
  706. X    break;
  707. X
  708. X    default:
  709. X    return(4);
  710. X    break;
  711. X    }
  712. X
  713. X    return(0);
  714. X}
  715. X
  716. X/*****************************************************/
  717. X/* The decisions made in create_formula_record       */
  718. X/* are carried out here, or in create_lotus_multiple */
  719. X/*****************************************************/
  720. X
  721. Xint
  722. Xcreate_lotus_formula(formbuf,dec_pl,c_col,s_col,s_row,e_col,e_row,rvalue)
  723. Xchar *formbuf;
  724. Xshort dec_pl, c_col, s_col, s_row, e_col, e_row;
  725. Xshort rvalue;
  726. X{
  727. X    int i;
  728. X    char *fc, *fp, *findex, *lrp, util_buf[256];
  729. X    double mult = 0.0;
  730. X
  731. X    char *namebuf = "~~~SUMAVGCNTMINMAXVARSTD+  -  *  /  %  NUL";
  732. X    unsigned short opcodes[14];/* = { 0xFF, 0x50, 0x51, 0x52, 0x53, 0x54, 0x57,
  733. X                 0x58, 0x09, 0x0A, 0x0B, 0x0C, 0x0C, 0xFF }; */
  734. X
  735. X    opcodes[0] = 0xFF; opcodes[1] = 0x50; opcodes[2] = 0x51; opcodes[3] = 0x52;
  736. X    opcodes[4] = 0x53; opcodes[5] = 0x54; opcodes[6] = 0x57; opcodes[7] = 0x58;
  737. X    opcodes[8] = 0x09; opcodes[9] = 0x0A; opcodes[10] = 0x0B;
  738. X    opcodes[11] = 0x0C; opcodes[12] = 0x0C; opcodes[13] = 0xFF;
  739. X
  740. X    /*** find which formula ***/
  741. X    fp = ++formbuf;
  742. X    *util_buf = '\0';
  743. X    strncat(util_buf,fp,3);
  744. X#ifdef DEBUG
  745. X
  746. X    fprintf(stderr,"util_buf holds formula string |%s|\n",util_buf);
  747. X#endif
  748. X    if ((findex = strstr(namebuf,util_buf)) == NULL) {
  749. X#ifdef DEBUG
  750. X      fprintf(stderr,"findex returns null!\n");
  751. X#endif
  752. X    return(4);
  753. X    }
  754. X
  755. X    lrp = (char *)(&FORMULAr);
  756. X
  757. X    *FORMULAr.format = (char)(0x80 + dec_pl);
  758. X    int2s(swapb(c_col),FORMULAr.column);
  759. X    int2s(swapb((unsigned short)current_row),FORMULAr.row);
  760. X    fc = FORMULAr.formula_code;
  761. X
  762. X    /** fill in the actual lotus formula **/
  763. X
  764. X    i = findex - namebuf;
  765. X    i = i / 3;
  766. X
  767. X    switch (i) {
  768. X
  769. X    case 1:        /* summation */
  770. X    case 2:        /* average */
  771. X    case 3:        /* count */
  772. X    case 4:        /* minimum */
  773. X    case 5:        /* maximum */
  774. X    case 6:        /* variance */
  775. X    case 7:        /* standard deviation */
  776. X
  777. X        *(fc++) = 0x02;        /* range */
  778. X        create_formula_range(fc,c_col,s_col,s_row,e_col,e_row,1);
  779. X        fc += 8;
  780. X        *(fc++) = opcodes[i];    /* lotus opcode */
  781. X        *(fc++) = 0x01;        /* make it a variable? */
  782. X        *(fc++) = 0x03;        /* end of formula - return */
  783. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  784. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  785. X        output_lotus_record(lrp);
  786. X        break;
  787. X
  788. X    case 8:        /* addition */
  789. X    case 10:        /* multiplication */
  790. X
  791. X        *(fc++) = 0x01;        /* variable */
  792. X        create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  793. X        fc += 4;
  794. X        *(fc++) = 0x01;        /* variable */
  795. X        create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  796. X        fc += 4;
  797. X        *(fc++) = opcodes[i];    /* lotus opcode */
  798. X        *(fc++) = 0x04;        /* parentheses? */
  799. X        *(fc++) = 0x03;        /* end of formula - return */
  800. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  801. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  802. X        output_lotus_record(lrp);
  803. X        break;
  804. X
  805. X    case 12:        /* percent (not a lotus function) */
  806. X        mult = 100.00;
  807. X        if (dec_pl < 1)
  808. X        *FORMULAr.format = (char)(0x80 + 2);
  809. X    case 9:        /* subtraction */
  810. X    case 11:        /* division */
  811. X
  812. X        *(fc++) = 0x01;        /* variable */
  813. X        if (rvalue > -1)
  814. X        create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  815. X        else
  816. X        create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  817. X        fc += 4;
  818. X        *(fc++) = 0x01;        /* variable */
  819. X        if (rvalue > -1)
  820. X        create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  821. X        else
  822. X        create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  823. X        fc += 4;
  824. X        *(fc++) = opcodes[i];    /* lotus opcode */
  825. X        if (mult != 0.0) {
  826. X        *(fc++) = 0x00;        /* constant */
  827. X        stdbl(mult,fc);
  828. X        fc += 8;
  829. X        *(fc++) = 0x0B;        /* multiply */
  830. X        }
  831. X        *(fc++) = 0x04;        /* parentheses? */
  832. X        *(fc++) = 0x03;        /* end of formula - return */
  833. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  834. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  835. X        output_lotus_record(lrp);
  836. X        break;
  837. X    case 13:        /* null - do nothing */
  838. X        ;
  839. X        break;
  840. X
  841. X    default:
  842. X        return(1);
  843. X        break;
  844. X    }
  845. X
  846. X    return(0);
  847. X}
  848. X
  849. X/*************************************************/
  850. X/* create a multiple formula (addition of two    */
  851. X/* formulae, row and column)                     */
  852. X/*************************************************/
  853. X
  854. Xint
  855. Xcreate_lotus_multiple(formbuf,dec_pl,c_col,s_col,s_row,e_col,e_row,
  856. X                                 s2_col,s2_row,e2_col,e2_row,rvalue)
  857. Xchar *formbuf;
  858. Xshort dec_pl, c_col, s_col, s_row, e_col, e_row;
  859. Xshort s2_col, s2_row, e2_col, e2_row;
  860. Xshort rvalue;
  861. X{
  862. X    int i;
  863. X    char *fc, *fp, *findex, *lrp, util_buf[256];
  864. X    double mult = 0.0;
  865. X
  866. X    char *namebuf = "~~~SUMAVGCNTMINMAXVARSTD+  -  *  /  %  NUL";
  867. X    unsigned short opcodes[14];/* = { 0xFF, 0x50, 0x51, 0x52, 0x53, 0x54, 0x57,
  868. X                 0x58, 0x09, 0x0A, 0x0B, 0x0C, 0x0C, 0xFF }; */
  869. X
  870. X    opcodes[0] = 0xFF; opcodes[1] = 0x50; opcodes[2] = 0x51; opcodes[3] = 0x52;
  871. X    opcodes[4] = 0x53; opcodes[5] = 0x54; opcodes[6] = 0x57; opcodes[7] = 0x58;
  872. X    opcodes[8] = 0x09; opcodes[9] = 0x0A; opcodes[10] = 0x0B;
  873. X    opcodes[11] = 0x0C; opcodes[12] = 0x0C; opcodes[13] = 0xFF;
  874. X
  875. X    /*** find which formula ***/
  876. X    fp = ++formbuf;
  877. X    *util_buf = '\0';
  878. X    strncat(util_buf,fp,3);
  879. X#ifdef DEBUG
  880. X    fprintf(stderr,"util_buf holds formula string |%s|\n",util_buf);
  881. X#endif
  882. X    if ((findex = strstr(namebuf,util_buf)) == NULL) {
  883. X#ifdef DEBUG
  884. X      fprintf(stderr,"findex returns null!\n");
  885. X#endif
  886. X    return(4);
  887. X    }
  888. X
  889. X    lrp = (char *)(&FORMULAr);
  890. X
  891. X    *FORMULAr.format = (char)(0x80 + dec_pl);
  892. X    int2s(swapb(c_col),FORMULAr.column);
  893. X    int2s(swapb((unsigned short)current_row),FORMULAr.row);
  894. X    fc = FORMULAr.formula_code;
  895. X
  896. X    /** fill in the actual lotus formula **/
  897. X
  898. X    i = findex - namebuf;
  899. X    i = i / 3;
  900. X
  901. X    switch (i) {
  902. X
  903. X    case 1:        /* summation */
  904. X    case 2:        /* average */
  905. X    case 3:        /* count */
  906. X    case 4:        /* minimum */
  907. X    case 5:        /* maximum */
  908. X    case 6:        /* variance */
  909. X    case 7:        /* standard deviation */
  910. X
  911. X        *(fc++) = 0x02;        /* range */
  912. X        create_formula_range(fc,c_col,s_col,s_row,e_col,e_row,1);
  913. X        fc += 8;
  914. X        *(fc++) = opcodes[i];    /* lotus opcode */
  915. X        *(fc++) = 0x01;        /* make it a variable? */
  916. X        *(fc++) = 0x02;        /* range */
  917. X        create_formula_range(fc,c_col,s2_col,s2_row,e2_col,e2_row,1);
  918. X        fc += 8;
  919. X        *(fc++) = opcodes[i];    /* lotus opcode */
  920. X        *(fc++) = 0x01;        /* make it another variable? */
  921. X        *(fc++) = 0x09;        /* addition of two ranges */
  922. X        *(fc++) = 0x04;        /* parentheses? */
  923. X        *(fc++) = 0x03;        /* end of formula - return */
  924. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  925. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  926. X        output_lotus_record(lrp);
  927. X        break;
  928. X
  929. X    case 8:        /* addition */
  930. X    case 10:        /* multiplication */
  931. X
  932. X        *(fc++) = 0x01;        /* variable */
  933. X        create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  934. X        fc += 4;
  935. X        *(fc++) = 0x01;        /* variable */
  936. X        create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  937. X        fc += 4;
  938. X        *(fc++) = opcodes[i];    /* lotus opcode */
  939. X        *(fc++) = 0x04;        /* parentheses? */
  940. X        *(fc++) = 0x03;        /* end of formula - return */
  941. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  942. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  943. X        output_lotus_record(lrp);
  944. X        break;
  945. X
  946. X    case 12:        /* percent (not a lotus function) */
  947. X        mult = 100.00;
  948. X        if (dec_pl < 1)
  949. X        *FORMULAr.format = (char)(0x80 + 2);
  950. X    case 9:        /* subtraction */
  951. X    case 11:        /* division */
  952. X
  953. X        *(fc++) = 0x01;        /* variable */
  954. X        if (rvalue > -1)
  955. X        create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  956. X        else
  957. X        create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  958. X        fc += 4;
  959. X        *(fc++) = 0x01;        /* variable */
  960. X        if (rvalue > -1)
  961. X        create_formula_range(fc,c_col,s_col,s_row,0,0,0);
  962. X        else
  963. X        create_formula_range(fc,c_col,e_col,e_row,0,0,0);
  964. X        fc += 4;
  965. X        *(fc++) = opcodes[i];    /* lotus opcode */
  966. X        if (mult != 0.0) {
  967. X        *(fc++) = 0x00;        /* constant */
  968. X        stdbl(mult,fc);
  969. X        fc += 8;
  970. X        *(fc++) = 0x0B;        /* multiply */
  971. X        }
  972. X        *(fc++) = 0x04;        /* parentheses? */
  973. X        *(fc++) = 0x03;        /* end of formula - return */
  974. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code)),FORMULAr.formula_size);
  975. X        int2s(swapb((unsigned short)(fc - FORMULAr.formula_code + 15)),FORMULAr.record_length);
  976. X        output_lotus_record(lrp);
  977. X        break;
  978. X    case 13:        /* null - do nothing */
  979. X        ;
  980. X        break;
  981. X
  982. X    default:
  983. X        return(1);
  984. X        break;
  985. X    }
  986. X
  987. X    return(0);
  988. X}
  989. X
  990. X/*****************************************/
  991. X/* output a lotus record -- note that    */
  992. X/* the length of the record is contained */
  993. X/* in the record itself (bytes 2-3)      */
  994. X/* minus the 4 bytes of opcode+length    */
  995. X/*****************************************/
  996. X
  997. Xint
  998. Xoutput_lotus_record(record_pointer)
  999. Xchar *record_pointer;
  1000. X{
  1001. X    int i, fstatus;
  1002. X    unsigned short total_length = 0;
  1003. X
  1004. X    total_length = swapb((unsigned short)s2int(record_pointer + 2)) + 4;
  1005. X
  1006. X    for (i = 0; i < total_length; i++)
  1007. X    fstatus = putc(*record_pointer++,outfile);
  1008. X
  1009. X    current_offset += (long)total_length;
  1010. X
  1011. X    return(fstatus);
  1012. X
  1013. X}
  1014. X
  1015. X/***********************************/
  1016. X/* our own getline -- like fgets,  */
  1017. X/* just returns null-term string   */
  1018. X/* instead of newline, and length  */
  1019. X/* instead of pointer              */
  1020. X/***********************************/
  1021. X
  1022. Xint
  1023. Xgetline(s,lim,stream)
  1024. Xchar s[];
  1025. Xint lim;
  1026. Xregister FILE *stream;
  1027. X{
  1028. X    int c, i;
  1029. X
  1030. X    i = 0;
  1031. X    while (--lim > 0 && (c = getc(stream)) != EOF && c != '\n')
  1032. X      s[i++] = c;
  1033. X
  1034. X    if (c == EOF)
  1035. X    return(c);
  1036. X
  1037. X    s[i] = '\0';
  1038. X    current_row++;
  1039. X
  1040. X    return(i);
  1041. X
  1042. X}
  1043. X
  1044. X/******************************/
  1045. X/* machine dependent routines */
  1046. X/******************************/
  1047. X
  1048. Xint
  1049. Xstdbl(value,ptr)
  1050. Xdouble value;
  1051. Xchar *ptr;
  1052. X{
  1053. X    int i = 7;
  1054. X    char *dp;
  1055. X
  1056. X    dp = (char *)&value;
  1057. X    while (i > -1)
  1058. X    *ptr++ = *(dp + (i--));
  1059. X}
  1060. X
  1061. X/*****************************************/
  1062. X/* return a new string, with the first   */
  1063. X/* character non-whitespace.  Look out;  */
  1064. X/* it does clobber the passed contents,  */
  1065. X/* but returns the length of the result .*/
  1066. X/*****************************************/
  1067. X
  1068. Xint
  1069. Xtrim(p)
  1070. Xregister char *p;
  1071. X{
  1072. X    int i;
  1073. X    char *hp, *np;
  1074. X
  1075. X    hp = np = p;
  1076. X
  1077. X    while(*p && (*p == ' ' || *p == '\t'))
  1078. X    p++;
  1079. X    while (*p)
  1080. X    *np++ = *p++;
  1081. X
  1082. X    *np = '\0';
  1083. X    for (i = strlen(hp) - 1; (i > 0) && (*(hp+i) == ' '); i--)
  1084. X    *(--np) = '\0';
  1085. X
  1086. X    return((int)(np - hp));
  1087. X}
  1088. X
  1089. X/**********************************************************************/
  1090. X/* create a lotus formula range...lotus cell addresses are of two     */
  1091. X/* types, absolute and relative.  Absolute address place 0,0 at the   *
  1092. X/* upper left corner of the spreadsheet.  Relative address are        */
  1093. X/* "circular" relative, and are all negative.  The current cell is    */
  1094. X/* address -32768 (the maximum 16-bit signed negative).  The cell     */
  1095. X/* position immediately "above" or "left" of the current cell is      */
  1096. X/* -1, decreasing as you "decrease" your position.  The cell position */
  1097. X/* immediately "below" or "right" of the current cell is -32767,      */
  1098. X/* increasing as you "increase" your position.                        */
  1099. X/*                                                                    */
  1100. X/* The "type" parameter is simply a flag to indicate whether the      */
  1101. X/* range is a true range, all four parameters (type = 1), or whether  */
  1102. X/* it is just a column position (type = 0).  In the latter case, only */
  1103. X/* the start column and start row are done.                           */
  1104. X/*                                                                    */
  1105. X/* Oh, by the way;  don't forget to byte-swap each 16-bits if your    */
  1106. X/* computer is a big-endian!                                          */
  1107. X/**********************************************************************/
  1108. X
  1109. Xint
  1110. Xcreate_formula_range(range_ptr,c_col,s_col,s_row,e_col,e_row,type)
  1111. Xchar *range_ptr;
  1112. Xshort c_col, s_col, s_row, e_col, e_row;
  1113. Xint type;
  1114. X{
  1115. X    short rel_ptr;
  1116. X    char *p;
  1117. X
  1118. X    p = range_ptr;
  1119. X
  1120. X    rel_ptr = (s_col < c_col) ? (s_col - c_col - 8192) : (s_col - c_col - 32768);
  1121. X    int2s(swapb((unsigned short)rel_ptr),p);
  1122. X    p += 2;
  1123. X    rel_ptr = (s_row < current_row) ? (s_row - current_row - 8192) : (s_row - current_row - 32768);
  1124. X    int2s(swapb((unsigned short)rel_ptr),p);
  1125. X    if (type) {
  1126. X    p += 2;
  1127. X    rel_ptr = (e_col < c_col) ? (e_col - c_col - 8192) : (e_col - c_col - 32768);
  1128. X    int2s(swapb((unsigned short)rel_ptr),p);
  1129. X    p += 2;
  1130. X    rel_ptr = (e_row < current_row) ? (e_row - current_row - 8192) : (e_row - current_row - 32768);
  1131. X    int2s(swapb((unsigned short)rel_ptr),p);
  1132. X    }
  1133. X
  1134. X    return(0);
  1135. X
  1136. X}
  1137. X
  1138. X
  1139. X/**********************************************/
  1140. X/* Routine to count number of decimal places  */
  1141. X/* assumes that numbuf is already "trimmed"   */
  1142. X/* (i.e., no leading white space).            */
  1143. X/**********************************************/
  1144. X
  1145. Xshort
  1146. Xdecimals(numbuf)
  1147. Xchar    *numbuf;
  1148. X{
  1149. X    char *c, *p;
  1150. X
  1151. X    if ((p = strchr(numbuf,'.')) == NULL)
  1152. X        return((short)0);
  1153. X
  1154. X    c = ++p;
  1155. X    while (*c && isdigit(*c))
  1156. X        c++;
  1157. X
  1158. X    return((short)(c - p));
  1159. X}
  1160. END_OF_FILE
  1161. if test 33229 -ne `wc -c <'conv123.c'`; then
  1162.     echo shar: \"'conv123.c'\" unpacked with wrong size!
  1163. fi
  1164. # end of 'conv123.c'
  1165. fi
  1166. if test -f 'grph123.c' -a "${1}" != "-c" ; then 
  1167.   echo shar: Will not clobber existing file \"'grph123.c'\"
  1168. else
  1169. echo shar: Extracting \"'grph123.c'\" \(29598 characters\)
  1170. sed "s/^X//" >'grph123.c' <<'END_OF_FILE'
  1171. X#include <stdio.h>
  1172. X#include <fcntl.h>
  1173. X#include <string.h>
  1174. X#include <stdlib.h>
  1175. X
  1176. X#include "lotus.h"
  1177. X#include "swapb.h"
  1178. X
  1179. X
  1180. X#define MAXHEADLINES 2
  1181. X#define MAXROWS 8192    /* dependent on 12-bit maximum value */
  1182. X#define MAXCOLS 53    /* arbitrary */
  1183. X#define MAXCOLWD 39    /* used only to calculate max input rec length */
  1184. X            /* and x data value length                     */
  1185. X#define MAXINRECLEN (MAXCOLS * MAXCOLWD + 5 * MAXCOLS)
  1186. X#define COLEXTEND 2    /* amount to widen columns for 123 */
  1187. X
  1188. XFILE *infile, *outfile;
  1189. X
  1190. Xshort current_row, current_graph;
  1191. Xlong current_offset;    /* output file offset */
  1192. X
  1193. Xshort col_width[MAXCOLS], col_pos[MAXCOLS], col_type[MAXCOLS];
  1194. Xshort formula_start_row[MAXCOLS], formula_end_row[MAXCOLS];
  1195. Xshort formula_start_col, formula_end_col;
  1196. Xshort decimals(), dec_pl, col_dec_pl[MAXCOLS], row_dec_pl;
  1197. X
  1198. Xint  y_decpl[6];
  1199. Xchar *qtstr();
  1200. X
  1201. X/***********************************/
  1202. X/* declare lotus record structures */
  1203. X/***********************************/
  1204. X
  1205. XBOF BOFr;
  1206. X
  1207. XRANGE RANGEr;
  1208. XCALCCOUNT CALCCOUNTr;
  1209. XCALCMODE CALCMODEr;
  1210. XCALCORDER CALCORDERr;
  1211. XSPLIT SPLITr;
  1212. XSYNC SYNCr;
  1213. XWINDOW1 WINDOW1r;
  1214. XCOLW1 COLW1r;
  1215. XNGRAPH NGRAPHr;
  1216. XTABLE TABLEr;
  1217. XQRANGE QRANGEr;
  1218. XPRANGE PRANGEr;
  1219. XLABEL LABELr;
  1220. X/*  INTEGER INTEGERr; */
  1221. XNUMBER NUMBERr;
  1222. XFORMULA FORMULAr;    
  1223. XLEOF LEOFr;
  1224. X
  1225. X/* now for the main data structure, which has limits -- this  */
  1226. X/* monster is (somewhat) necessary in order to allow the      */
  1227. X/* flexibility of getting all the data (and labels) in before */
  1228. X/* writing the NGRAPH record...                               */
  1229. X
  1230. Xstruct {
  1231. X    char    x_item[MAXCOLWD+1];
  1232. X    double    y_item[6];
  1233. X    short    number_of_labels;
  1234. X    char    y_label[6][20];
  1235. X} graph_data[MAXCOLS];
  1236. X
  1237. X/*****************************/
  1238. X/* finally, we begin         */
  1239. X/*****************************/
  1240. X
  1241. Xmain(argc,argv)
  1242. Xint argc;
  1243. Xchar *argv[];
  1244. X{
  1245. X
  1246. X/**********************/
  1247. X/* main declarations  */
  1248. X/**********************/
  1249. X
  1250. X    int fstat;
  1251. X    char c;
  1252. X    char *p, *bp, *cp, *fp, *sp, *sstat;
  1253. X    char inbuf[MAXINRECLEN + 1], util_buf[MAXINRECLEN + 1], util_buf2[100];
  1254. X    char infilename[96];
  1255. X    char outfilename[96];
  1256. X    char blank_buf[80];
  1257. X
  1258. X    int i, j, k, l, debug, fs, us, type_ind, label_ready;
  1259. X
  1260. X    unsigned short i1, j1, l1;
  1261. X
  1262. X    short number_of_cols, number_of_rows;
  1263. X    short number_of_graphs, header_lines, max_title;
  1264. X    char   str_value[6][41];
  1265. X    double dbl_value[6];
  1266. X
  1267. X    long RANGE_offset;
  1268. X
  1269. X/**************************************/
  1270. X/* initialize lotus record structures */
  1271. X/**************************************/
  1272. X
  1273. X    int2s(swapb(BOF_op),BOFr.opcode);
  1274. X    int2s(swapb(BOF_len),BOFr.record_length);
  1275. X    int2s(swapb((unsigned short)1030),BOFr.ff_version);
  1276. X
  1277. X    int2s(swapb(RANGE_op),RANGEr.opcode);
  1278. X    int2s(swapb(RANGE_len),RANGEr.record_length);
  1279. X    int2s(swapb((unsigned short)0),RANGEr.start_column);
  1280. X    int2s(swapb((unsigned short)0),RANGEr.start_row);
  1281. X    int2s(swapb((unsigned short)0),RANGEr.end_column);
  1282. X    int2s(swapb((unsigned short)0),RANGEr.end_row);
  1283. X
  1284. X    int2s(swapb(CALCCOUNT_op),CALCCOUNTr.opcode);
  1285. X    int2s(swapb(CALCCOUNT_len),CALCCOUNTr.record_length);
  1286. X    *CALCCOUNTr.iteration_count = 1;
  1287. X
  1288. X    int2s(swapb(CALCMODE_op),CALCMODEr.opcode);
  1289. X    int2s(swapb(CALCMODE_len),CALCMODEr.record_length);
  1290. X    *CALCMODEr.recalculation = 0xFF;    /* automatic recalc */
  1291. X
  1292. X    int2s(swapb(CALCORDER_op),CALCORDERr.opcode);
  1293. X    int2s(swapb(CALCORDER_len),CALCORDERr.record_length);
  1294. X    *CALCORDERr.calc_order = 0x00;    /* natural order */
  1295. X
  1296. X    int2s(swapb(SPLIT_op),SPLITr.opcode);
  1297. X    int2s(swapb(SPLIT_len),SPLITr.record_length);
  1298. X    *SPLITr.window_split = 0x00;    /* no window split */
  1299. X
  1300. X    int2s(swapb(SYNC_op),SYNCr.opcode);
  1301. X    int2s(swapb(SYNC_len),SYNCr.record_length);
  1302. X    *SYNCr.window_sync = 0xFF;        /* window synchronized */
  1303. X
  1304. X    int2s(swapb(WINDOW1_op),WINDOW1r.opcode);
  1305. X    int2s(swapb(WINDOW1_len),WINDOW1r.record_length);
  1306. X    int2s(swapb((unsigned short)0),WINDOW1r.cc_column);
  1307. X    int2s(swapb((unsigned short)0),WINDOW1r.cc_row);
  1308. X    *WINDOW1r.cell_format = 2;    /* two decimal places */
  1309. X    *WINDOW1r.unused1 = 0;
  1310. X    int2s(swapb((unsigned short)9),WINDOW1r.column_width);
  1311. X    int2s(swapb((unsigned short)8),WINDOW1r.ncol_on_screen);
  1312. X    int2s(swapb((unsigned short)20),WINDOW1r.nrow_on_screen);
  1313. X    int2s(swapb((unsigned short)0),WINDOW1r.leftmost_column);
  1314. X    int2s(swapb((unsigned short)0),WINDOW1r.top_row);
  1315. X    int2s(swapb((unsigned short)0),WINDOW1r.ntitle_col);
  1316. X    int2s(swapb((unsigned short)0),WINDOW1r.ntitle_row);
  1317. X    int2s(swapb((unsigned short)0),WINDOW1r.ltitle_col);
  1318. X    int2s(swapb((unsigned short)0),WINDOW1r.ttitle_row);
  1319. X    int2s(swapb((unsigned short)4),WINDOW1r.borderwd_col);
  1320. X    int2s(swapb((unsigned short)4),WINDOW1r.borderwd_row);
  1321. X    int2s(swapb((unsigned short)72),WINDOW1r.window_width);
  1322. X    *WINDOW1r.unused2 = 0;
  1323. X    *WINDOW1r.unused3 = 0;
  1324. X
  1325. X    /* there are multiple of these, so just init basic elements for now */
  1326. X    int2s(swapb(COLW1_op),COLW1r.opcode);
  1327. X    int2s(swapb(COLW1_len),COLW1r.record_length);
  1328. X
  1329. X
  1330. X    /* there are multiple of these, so just init basic elements for now */
  1331. X    int2s(swapb(NGRAPH_op),NGRAPHr.opcode);
  1332. X    int2s(swapb(NGRAPH_len),NGRAPHr.record_length);
  1333. X
  1334. X
  1335. X    int2s(swapb(TABLE_op),TABLEr.opcode);
  1336. X    int2s(swapb(TABLE_len),TABLEr.record_length);
  1337. X    *TABLEr.table_ind = 0x00;        /* no table */
  1338. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.table_start_column);
  1339. X    int2s(swapb((unsigned short)0),TABLEr.table_start_row);
  1340. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.table_end_column);
  1341. X    int2s(swapb((unsigned short)0),TABLEr.table_end_row);
  1342. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.cell1_start_column);
  1343. X    int2s(swapb((unsigned short)0),TABLEr.cell1_start_row);
  1344. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.cell1_end_column);
  1345. X    int2s(swapb((unsigned short)0),TABLEr.cell1_end_row);
  1346. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.cell2_start_column);
  1347. X    int2s(swapb((unsigned short)0),TABLEr.cell2_start_row);
  1348. X    int2s(swapb((unsigned short)0xFFFF),TABLEr.cell2_end_column);
  1349. X    int2s(swapb((unsigned short)0),TABLEr.cell2_end_row);
  1350. X
  1351. X
  1352. X    int2s(swapb(QRANGE_op),QRANGEr.opcode);
  1353. X    int2s(swapb(QRANGE_len),QRANGEr.record_length);
  1354. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.input_start_column);
  1355. X    int2s(swapb((unsigned short)0),QRANGEr.input_start_row);
  1356. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.input_end_column);
  1357. X    int2s(swapb((unsigned short)0),QRANGEr.input_end_row);
  1358. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.output_start_column);
  1359. X    int2s(swapb((unsigned short)0),QRANGEr.output_start_row);
  1360. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.output_end_column);
  1361. X    int2s(swapb((unsigned short)0),QRANGEr.output_end_row);
  1362. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.criteria_start_column);
  1363. X    int2s(swapb((unsigned short)0),QRANGEr.criteria_start_row);
  1364. X    int2s(swapb((unsigned short)0xFFFF),QRANGEr.criteria_end_column);
  1365. X    int2s(swapb((unsigned short)0),QRANGEr.criteria_end_row);
  1366. X    *QRANGEr.command = 0;        /* no command */
  1367. X
  1368. X    int2s(swapb(PRANGE_op),PRANGEr.opcode);
  1369. X    int2s(swapb(PRANGE_len),PRANGEr.record_length);
  1370. X    int2s(swapb((unsigned short)0xFFFF),PRANGEr.start_column);
  1371. X    int2s(swapb((unsigned short)0),PRANGEr.start_row);
  1372. X    int2s(swapb((unsigned short)0xFFFF),PRANGEr.end_column);
  1373. X    int2s(swapb((unsigned short)0),PRANGEr.end_row);
  1374. X
  1375. X    int2s(swapb(LABEL_op),LABELr.opcode);
  1376. X    *LABELr.format = 0xFF;    /* lotus default */
  1377. X    *LABELr.position = 0x27;    /* single quote ('), left justified */
  1378. X
  1379. X
  1380. X    int2s(swapb(NUMBER_op),NUMBERr.opcode);
  1381. X    int2s(swapb(NUMBER_len),NUMBERr.record_length);
  1382. X    *NUMBERr.format = 0xFF;    /* lotus default */
  1383. X
  1384. X    int2s(swapb(FORMULA_op),FORMULAr.opcode);
  1385. X    *FORMULAr.format = 0xFF;    /* lotus default */
  1386. X    
  1387. X
  1388. X    int2s(swapb(LEOF_op),LEOFr.opcode);
  1389. X    int2s(swapb(LEOF_len),LEOFr.record_length);
  1390. X
  1391. X/************************************/
  1392. X/* Now some ordinary initialization */
  1393. X/************************************/
  1394. X
  1395. X    current_offset = 0L;
  1396. X    current_graph = 0;
  1397. X    type_ind = 0;
  1398. X
  1399. X    number_of_cols = 0;
  1400. X    number_of_rows = 0;
  1401. X    label_ready = 0;
  1402. X    max_title = 18;
  1403. X
  1404. X/*******************************/
  1405. X/* assign files                */
  1406. X/*******************************/
  1407. X
  1408. X    infile = stdin;            /* typical input is stdin (filter) */
  1409. X    outfile = stdout;            /* typical output is stdout (filter) */
  1410. X
  1411. X    debug = 0;                /* don't do it */
  1412. X
  1413. X/* Make sure blank_buf is initialized */
  1414. X
  1415. X    for (i = 0; i < 80; i++)
  1416. X    blank_buf[i] = ' ';
  1417. X
  1418. X/************************************/
  1419. X/* if there are input parameters,   */
  1420. X/* deal with them.                  */
  1421. X/************************************/
  1422. X
  1423. X    if (argc > 3) {
  1424. X     fprintf(stderr,"Allowed parameters are input and output filenames.\n");
  1425. X    return(1);
  1426. X    }
  1427. X
  1428. X/* open main data input file as a stream (maybe) */
  1429. X    if (argc > 1) {
  1430. X        fclose(infile);
  1431. X    strcpy(infilename,argv[1]);
  1432. X    if ((infile = fopen(infilename,"r")) == NULL) {
  1433. X        fprintf(stderr,"Open of input data file %s failed.\n",infilename);
  1434. X        return(1);
  1435. X    }
  1436. X    }
  1437. X
  1438. X/* create and open output file directly (maybe) */
  1439. X    if (argc > 2) {
  1440. X        fclose(outfile);
  1441. X    strcpy(outfilename,argv[2]);
  1442. X    if ((outfile = fopen(outfilename,"w+")) == NULL) {
  1443. X        fprintf(stderr,"open of output data file %s failed.\n",outfilename);
  1444. X        fclose(infile);
  1445. X        return;
  1446. X    }
  1447. X    }
  1448. X
  1449. X/************************************/
  1450. X/* now get to work translating it   */
  1451. X/************************************/
  1452. X
  1453. X    if (get_header_info(inbuf,&number_of_graphs,&header_lines))
  1454. X    return(1);
  1455. X    if (number_of_graphs < 1) {
  1456. X    fprintf(stderr,"No graphs were detected...check input file.");
  1457. X    exit(1);
  1458. X    }
  1459. X
  1460. X    current_row = number_of_graphs + 6;    /* leave room for titles & stuff */
  1461. X
  1462. X/* fprintf(stderr,"Number of graphs: %d\n",number_of_graphs); */
  1463. X
  1464. X/************************************/
  1465. X/* we've got SOMETHING, so go ahead */
  1466. X/* and start the 123 output!        */
  1467. X/************************************/
  1468. X
  1469. X    p = (char *)(&BOFr);
  1470. X    fs = output_lotus_record(p);
  1471. X
  1472. X    p = (char *)(&CALCMODEr);
  1473. X    fs = output_lotus_record(p);
  1474. X
  1475. X#ifdef DEBUG
  1476. X    fprintf(stderr,"Offset after RANGE: %d\n",current_offset);
  1477. X#endif
  1478. X
  1479. X/**********************************/
  1480. X/* create header labels           */
  1481. X/**********************************/
  1482. X
  1483. X    create_lotus_label("Brooktree Corp. Confidential",0,0);
  1484. X    *LABELr.format = 0x7F;
  1485. X    create_lotus_label("Graph Name",0,2);
  1486. X    create_lotus_label("Graph Title",1,2);
  1487. X    create_lotus_label("================",0,3);
  1488. X    create_lotus_label("==============================",1,3);
  1489. X    *LABELr.format = 0xFF;
  1490. X
  1491. X/**********************************/
  1492. X/* do the real work, and process  */
  1493. X/* all lines in the file          */
  1494. X/**********************************/
  1495. X
  1496. X    while ((fs = getline(inbuf,MAXINRECLEN,infile)) != EOF) {
  1497. X
  1498. X/**    formula_start_col = -1;        /* start out pessimistic */
  1499. X/**    formula_end_col = -1; **/
  1500. X    row_dec_pl = 0;
  1501. X
  1502. X      if (trim(inbuf) > 0) {
  1503. X    type_ind = (int)(*inbuf);
  1504. X/* fprintf(stderr,"Now doing type: %c\n",*inbuf); */
  1505. X    switch (type_ind) {
  1506. X        case 'N':
  1507. X        case 'n':                /* graph name */
  1508. X/************************************/
  1509. X/* initialize named graph structure */
  1510. X/************************************/
  1511. X
  1512. X    sp = (char *)&NGRAPHr;
  1513. X    sp = sp + 4;                /* skip over opcode & size */
  1514. X    for (i = 0; i < (sizeof(NGRAPHr) - 4); i++)
  1515. X    *sp++ = '\0';
  1516. X    *NGRAPHr.graph_type = (char)(0x04);        /* line graph */
  1517. X    *NGRAPHr.x_format = (char)(0x71);
  1518. X    *NGRAPHr.y_format = (char)(0x71);
  1519. X    int2s(swapb((unsigned short)(0x01)),NGRAPHr.skip_factor);
  1520. X    for (i = 0; i < 6; i++) {
  1521. X    int2s((unsigned short)(0xFFFF),NGRAPHr.yd_range[i].y_start_col);
  1522. X    int2s((unsigned short)(0xFFFF),NGRAPHr.yd_range[i].y_end_col);
  1523. X    int2s((unsigned short)(0xFFFF),NGRAPHr.yl_range[i].y_start_col);
  1524. X    int2s((unsigned short)(0xFFFF),NGRAPHr.yl_range[i].y_end_col);
  1525. X    NGRAPHr.y_lformat[i] = (char)(0x03);
  1526. X    y_decpl[i] = 2;
  1527. X    }
  1528. X
  1529. X        strcpy(util_buf,&inbuf[1]);
  1530. X        us = trim(util_buf);
  1531. X        if (us > 0) {
  1532. X            sp = qtstr(util_buf,util_buf,15);
  1533. X            strcpy(NGRAPHr.graph_name,util_buf);
  1534. X        }
  1535. X        break;
  1536. X        case 'T':                /* First title */
  1537. X        strcpy(util_buf,&inbuf[1]);
  1538. X        us = trim(util_buf);
  1539. X        if (us > 0) {
  1540. X            sp = qtstr(util_buf,util_buf,39);
  1541. X            strcpy(NGRAPHr.first_title,util_buf);
  1542. X        }
  1543. X        break;
  1544. X        case 't':                /* Second title */
  1545. X        strcpy(util_buf,&inbuf[1]);
  1546. X        us = trim(util_buf);
  1547. X        if (us > 0) {
  1548. X            sp = qtstr(util_buf,util_buf,39);
  1549. X            strcpy(NGRAPHr.second_title,util_buf);
  1550. X        }
  1551. X        break;
  1552. X        case 'B':
  1553. X        case 'b':                /* x (bottom) title */
  1554. X        strcpy(util_buf,&inbuf[1]);
  1555. X        us = trim(util_buf);
  1556. X        if (us > 0) {
  1557. X            sp = qtstr(util_buf,util_buf,39);
  1558. X            strcpy(NGRAPHr.x_title,util_buf);
  1559. X            if (max_title < strlen(util_buf))
  1560. X            max_title = strlen(util_buf);
  1561. X        }
  1562. X        break;
  1563. X        case 'S':
  1564. X        case 's':                /* y (side) title */
  1565. X        strcpy(util_buf,&inbuf[1]);
  1566. X        us = trim(util_buf);
  1567. X        if (us > 0) {
  1568. X            sp = qtstr(util_buf,util_buf,39);
  1569. X            strcpy(NGRAPHr.y_title,util_buf);
  1570. X        }
  1571. X        break;
  1572. X        case 'G':
  1573. X        case 'g':
  1574. X        strcpy(util_buf,&inbuf[1]);
  1575. X        us = trim(util_buf);
  1576. X        if (us > 0) {
  1577. X            for (i = 0; i < 4; i++)
  1578. X            *str_value[i] = '\0';
  1579. X            us = sscanf(util_buf,"%s%s%s%s",str_value[0],
  1580. X                            str_value[1],
  1581. X                            str_value[2],
  1582. X                            str_value[3]);
  1583. X            if (us > 0) {
  1584. X            c = toupper((char)(*str_value[0]));
  1585. X            if (c == 'L')
  1586. X              *NGRAPHr.graph_type = (char)(0x04); /* line */
  1587. X            else
  1588. X            if (c == 'B')
  1589. X              *NGRAPHr.graph_type = (char)(0x01); /* bar */
  1590. X            else
  1591. X            if (c == 'P')
  1592. X              *NGRAPHr.graph_type = (char)(0x02); /* pie */
  1593. X            else
  1594. X            if (c == 'X')
  1595. X              *NGRAPHr.graph_type = (char)(0x00); /* xy */
  1596. X            else
  1597. X            if (c == 'S')
  1598. X              *NGRAPHr.graph_type = (char)(0x05); /* stacked bar */
  1599. X            }
  1600. X            if (us > 1) {
  1601. X            c = toupper((char)(*str_value[1]));
  1602. X            if (c == 'N')
  1603. X              *NGRAPHr.grid = (char)(0x00); /* none */
  1604. X            else
  1605. X            if (c == 'H')
  1606. X              *NGRAPHr.grid = (char)(0x01); /* horizontal */
  1607. X            else
  1608. X            if (c == 'V')
  1609. X              *NGRAPHr.grid = (char)(0x02); /* vertical */
  1610. X            else
  1611. X            if (c == 'B')
  1612. X              *NGRAPHr.grid = (char)(0x03); /* both horz & vert */
  1613. X            }
  1614. X            if (us > 2) {
  1615. X            c = toupper((char)(*str_value[2]));
  1616. X            if (c == 'B')
  1617. X              *NGRAPHr.color = (char)(0x00); /* black & white */
  1618. X            else
  1619. X            if (c == 'C')
  1620. X              *NGRAPHr.color = (char)(0xFF); /* color */
  1621. X            }
  1622. X            if (us > 3) {
  1623. X            sscanf(str_value[3],"%d",&i);
  1624. X            if (!i)
  1625. X                i = 1;
  1626. X            if (i > 256)
  1627. X                i = 256;
  1628. X            int2s(swapb((unsigned short)i),NGRAPHr.skip_factor);
  1629. X            }
  1630. X        }
  1631. X        break;
  1632. X        case 'l':                    /* legends */
  1633. X        strcpy(util_buf,&inbuf[1]);
  1634. X        us = trim(util_buf);
  1635. X        if (us > 0) {
  1636. X            sp = util_buf;
  1637. X            for (i = 0; *sp && (i < 6); i++) {
  1638. X            sp = qtstr(sp,util_buf2,19);
  1639. X            strcpy(NGRAPHr.y_legend[i],util_buf2);
  1640. X            }
  1641. X        }
  1642. X        break;
  1643. X        case 'P':
  1644. X        case 'p':
  1645. X        strcpy(util_buf,&inbuf[1]);
  1646. X        us = trim(util_buf);
  1647. X        if (us <= 0)
  1648. X            break;
  1649. X        us = sscanf(util_buf,"%d%d%d%d%d%d",&(y_decpl[0]),
  1650. X                            &(y_decpl[1]),
  1651. X                            &(y_decpl[2]),
  1652. X                            &(y_decpl[3]),
  1653. X                            &(y_decpl[4]),
  1654. X                            &(y_decpl[5]));
  1655. X                for (i = 0; i < us; i++) {
  1656. X                    if (y_decpl[i] < 0) y_decpl[i] = 0;
  1657. X                    if (y_decpl[6] > 6) y_decpl[i] = 6;
  1658. X        }
  1659. X/* fprintf(stderr,"decpl: %d %d %d %d %d %d\n",y_decpl[0],y_decpl[1],y_decpl[2],
  1660. X                    y_decpl[3],y_decpl[4],y_decpl[5]); */
  1661. X        break;
  1662. X        case 'D':
  1663. X        case 'd':
  1664. X        strcpy(util_buf,&inbuf[1]);
  1665. X        us = trim(util_buf);
  1666. X        if (us <= 0)
  1667. X            break;
  1668. X        sp = util_buf;
  1669. X        sp = qtstr(sp,util_buf2,39);
  1670. X        if (strlen(util_buf2) > 0) {
  1671. X            number_of_rows++;
  1672. X            if (number_of_rows > MAXCOLS) {
  1673. X            fprintf(stderr,
  1674. X                                  "Maximum number of data points exceeded.");
  1675. X            exit(3);
  1676. X            }
  1677. X            i = number_of_rows - 1;
  1678. X            strcpy(graph_data[i].x_item,util_buf2);
  1679. X            for (j = 0; j < 6; j++) {
  1680. X            graph_data[i].y_item[j] = -2000000000.0;
  1681. X            *(graph_data[i].y_label[j]) = '\0';
  1682. X            }
  1683. X            us = sscanf(sp,"%lf%lf%lf%lf%lf%lf",
  1684. X                &(graph_data[i].y_item[0]),
  1685. X                &(graph_data[i].y_item[1]),
  1686. X                &(graph_data[i].y_item[2]),
  1687. X                &(graph_data[i].y_item[3]),
  1688. X                &(graph_data[i].y_item[4]),
  1689. X                &(graph_data[i].y_item[5]));
  1690. X            number_of_cols = us > number_of_cols ? us : number_of_cols;
  1691. X            graph_data[i].number_of_labels = 0;
  1692. X            label_ready = 1;
  1693. X        }            
  1694. X        break;
  1695. X        case 'L':                    /* labels */
  1696. X        strcpy(util_buf,&inbuf[1]);
  1697. X        us = trim(util_buf);
  1698. X        if (us <= 0)
  1699. X            break;
  1700. X        if (!label_ready)
  1701. X            break;
  1702. X        i = number_of_rows - 1;
  1703. X        sp = util_buf;
  1704. X        for (j = 0; *sp && (j < 6); j++) {
  1705. X            sp = qtstr(sp,util_buf2,19);
  1706. X            strcpy(graph_data[i].y_label[j],util_buf2);
  1707. X            (graph_data[i].number_of_labels)++;
  1708. X        }
  1709. X        label_ready = 0;
  1710. X
  1711. X        break;
  1712. X        case 'X':
  1713. X        case 'x':
  1714. X        strcpy(util_buf,&inbuf[1]);
  1715. X        us = trim(util_buf);
  1716. X        if (us > 0) {
  1717. X            us = sscanf(util_buf,"%lf%lf",&dbl_value[0],&dbl_value[1]);
  1718. X            if (us > 0) stdbl(dbl_value[0],NGRAPHr.x_low_limit);
  1719. X            if (us > 1) stdbl(dbl_value[1],NGRAPHr.x_up_limit);
  1720. X            *NGRAPHr.x_scale = (char)(0xFF);
  1721. X        }
  1722. X        break;
  1723. X        case 'Y':
  1724. X        case 'y':
  1725. X        strcpy(util_buf,&inbuf[1]);
  1726. X        us = trim(util_buf);
  1727. X        if (us > 0) {
  1728. X            us = sscanf(util_buf,"%lf%lf",&dbl_value[0],&dbl_value[1]);
  1729. X            if (us > 0) stdbl(dbl_value[0],NGRAPHr.y_low_limit);
  1730. X            if (us > 1) stdbl(dbl_value[1],NGRAPHr.y_up_limit);
  1731. X            *NGRAPHr.y_scale = (char)(0xFF);
  1732. X        }
  1733. X        break;
  1734. X        case 'F':
  1735. X        case 'f':
  1736. X        strcpy(util_buf,&inbuf[1]);
  1737. X        us = trim(util_buf);
  1738. X        if (us > 0) {
  1739. X            us = sscanf(util_buf,"%s%s%s%s%s%s",str_value[0],
  1740. X                          str_value[1],
  1741. X                          str_value[2],
  1742. X                          str_value[3],
  1743. X                          str_value[4],
  1744. X                          str_value[5]);
  1745. X            for (i = 0; i < us; i++) {
  1746. X            c = toupper((char)(*str_value[i]));
  1747. X            if (c == 'N')
  1748. X              NGRAPHr.y_lformat[i] = (char)(0x00); /* none */
  1749. X            else
  1750. X            if (c == 'L')
  1751. X              NGRAPHr.y_lformat[i] = (char)(0x01); /* line */
  1752. X            else
  1753. X            if (c == 'S')
  1754. X              NGRAPHr.y_lformat[i] = (char)(0x02); /* symbol */
  1755. X            else
  1756. X            if (c == 'B')
  1757. X              NGRAPHr.y_lformat[i] = (char)(0x03); /* both l & s */
  1758. X            }
  1759. X          }
  1760. X        break;
  1761. X        case 'A':
  1762. X        case 'a':
  1763. X        strcpy(util_buf,&inbuf[1]);
  1764. X        us = trim(util_buf);
  1765. X        if (us > 0) {
  1766. X            us = sscanf(util_buf,"%s%s%s%s%s%s",str_value[0],
  1767. X                          str_value[1],
  1768. X                          str_value[2],
  1769. X                          str_value[3],
  1770. X                          str_value[4],
  1771. X                          str_value[5]);
  1772. X            for (i = 0; i < us; i++) {
  1773. X            c = toupper((char)(*str_value[i]));
  1774. X            if (c == 'C')
  1775. X              NGRAPHr.y_dlalign[i] = (char)(0x00); /* none */
  1776. X            else
  1777. X            if (c == 'R')
  1778. X              NGRAPHr.y_dlalign[i] = (char)(0x01); /* line */
  1779. X            else
  1780. X            if (c == 'B')
  1781. X              NGRAPHr.y_dlalign[i] = (char)(0x02); /* symbol */
  1782. X            else
  1783. X            if (c == 'L')
  1784. X              NGRAPHr.y_dlalign[i] = (char)(0x03); /* both l & s */
  1785. X            else
  1786. X            if (c == 'A')
  1787. X              NGRAPHr.y_dlalign[i] = (char)(0x04); /* both l & s */
  1788. X            }
  1789. X          }
  1790. X        break;
  1791. X        case 'E':
  1792. X        case 'e':
  1793. X
  1794. X        if (number_of_cols <= 0)    /* if there's no y-data, */
  1795. X            break;            /* just bail out         */
  1796. X
  1797. X        /* how about setting the first (0) column width  */
  1798. X
  1799. X        p = (char *)(&COLW1r);
  1800. X        int2s(swapb((unsigned short)0),COLW1r.column_number);
  1801. X        int2s(swapb(max_title),COLW1r.column_width);
  1802. X        output_lotus_record(p);
  1803. X
  1804. X        /* now let's put out the table of contents info */
  1805. X        *LABELr.position = 0x27;    /* single quote ('), lj  */
  1806. X
  1807. X        p = (char *)(&LABELr);
  1808. X        j1 = 0; i1 = ++current_graph + 3;
  1809. X         create_lotus_label(NGRAPHr.graph_name,j1,i1);
  1810. X        j1 = 1;
  1811. X        create_lotus_label(NGRAPHr.first_title,j1,i1);
  1812. X
  1813. X        /* Data values header */
  1814. X        j1 = 0; i1 = current_row++;
  1815. X        sprintf(util_buf,"Data for graph: %s (%s)",
  1816. X                  NGRAPHr.graph_name,NGRAPHr.first_title);
  1817. X        *LABELr.format = 0x7F;    /* lotus default */
  1818. X        create_lotus_label(util_buf,j1,i1);
  1819. X        *LABELr.format = 0xFF;    /* lotus default */
  1820. X
  1821. X
  1822. X        /* the x-value and y-value legends and ranges comes next */
  1823. X        j1 = 0; i1 = current_row;
  1824. X        create_lotus_label(NGRAPHr.x_title,j1,i1);
  1825. X
  1826. X        int2s(swapb((unsigned short)1),NGRAPHr.x_start_col);
  1827. X        int2s(swapb(i1),NGRAPHr.x_start_row);
  1828. X        int2s(swapb(number_of_rows),NGRAPHr.x_end_col);
  1829. X        int2s(swapb(i1),NGRAPHr.x_end_row);
  1830. X
  1831. X        for (j = 0; j < number_of_cols; j++) {
  1832. X            i1 = current_row + j + 1;
  1833. X            create_lotus_label(NGRAPHr.y_legend[j],j1,i1);
  1834. X        }
  1835. X
  1836. X        for (j = 0; j < number_of_cols; j++) {
  1837. X            i1 = current_row + j + 1;
  1838. X
  1839. X            int2s(swapb((unsigned short)1),
  1840. X                          NGRAPHr.yd_range[j].y_start_col);
  1841. X            int2s(swapb(i1),NGRAPHr.yd_range[j].y_start_row);
  1842. X            int2s(swapb(number_of_rows),NGRAPHr.yd_range[j].y_end_col);
  1843. X            int2s(swapb(i1),NGRAPHr.yd_range[j].y_end_row);
  1844. X
  1845. X        /* the data-label range comes next; even if no labels */
  1846. X        /* note that this limits a graph to 127 data points   */
  1847. X            int2s(swapb((unsigned short)(number_of_rows + 2)),
  1848. X                          NGRAPHr.yl_range[j].y_start_col);
  1849. X            int2s(swapb(i1),NGRAPHr.yl_range[j].y_start_row);
  1850. X            int2s(swapb((unsigned short)((2 * number_of_rows) + 2)),
  1851. X                        NGRAPHr.yl_range[j].y_end_col);
  1852. X            int2s(swapb(i1),NGRAPHr.yl_range[j].y_end_row);
  1853. X
  1854. X        }
  1855. X
  1856. X        /* let's write that graph record! */
  1857. X        p = (char *)(&NGRAPHr);
  1858. X        output_lotus_record(p);
  1859. X
  1860. X        /*******************************************************/
  1861. X        /* now for the data values (at last!)                  */
  1862. X        /*******************************************************/
  1863. X        *LABELr.position = 0x22;    /* double quote ("), rj */
  1864. X
  1865. X        for (i = 0; i < number_of_rows; i++) {
  1866. X            /* set column width, hard-coded for now */
  1867. X            p = (char *)(&COLW1r);
  1868. X            j1 = i + 1;
  1869. X            i1 = 11 + COLEXTEND;
  1870. X            int2s(swapb(j1),COLW1r.column_number);
  1871. X            int2s(swapb(i1),COLW1r.column_width);
  1872. X            output_lotus_record(p);
  1873. X
  1874. X            /* now for the independent data value (x-value) */
  1875. X            j1 = i + 1; i1 = current_row;
  1876. X            if (*NGRAPHr.graph_type)
  1877. X            create_lotus_label(graph_data[i].x_item,j1,i1);
  1878. X            else {
  1879. X            us = sscanf(graph_data[i].x_item,"%lf",&dbl_value[0]);
  1880. X            if (us && (dbl_value[0] > -2000000000.0))
  1881. X                create_lotus_number(dbl_value[0],j1,i1,2);
  1882. X            }
  1883. X
  1884. X            /* now for the dependent data values (y-values) */
  1885. X            /* put out the numbers, and labels if any       */
  1886. X            *LABELr.position = 0x27;    /* single quote ('), lj */
  1887. X            j1 = i + 1;
  1888. X            for (j = 0; j < number_of_cols; j++) {
  1889. X            dec_pl = y_decpl[j];
  1890. X            i1 = current_row + j + 1;
  1891. X            if (graph_data[i].y_item[j] > -2000000000.0)
  1892. X              create_lotus_number(graph_data[i].y_item[j],
  1893. X                                j1,i1,dec_pl);
  1894. X            if (graph_data[i].number_of_labels >= j) {
  1895. X                l1 = j1 + number_of_rows + 1;
  1896. X                create_lotus_label(graph_data[i].y_label[j],l1,i1);
  1897. X            }
  1898. X            }
  1899. X            *LABELr.position = 0x22;    /* double quote ("), rj */
  1900. X        }
  1901. X
  1902. X        current_row += number_of_cols + 2;
  1903. X
  1904. X        number_of_cols = 0;
  1905. X        number_of_rows = 0;
  1906. X        label_ready = 0;
  1907. X/*        max_title = 18;  */
  1908. X
  1909. X        break;
  1910. X        case '#':
  1911. X        break;
  1912. X        default:
  1913. X        fprintf(stderr,"Unknown record type!\n");
  1914. X        break;
  1915. X    }
  1916. X      }
  1917. X    } /* end while */
  1918. X
  1919. X/*********************/
  1920. X/* end of lotus file */
  1921. X/*********************/
  1922. X
  1923. X    p = (char *)(&LEOFr);
  1924. X    output_lotus_record(p);
  1925. X
  1926. X}
  1927. X
  1928. X/*****************************************/
  1929. X/* scan input file for number of graphs, */
  1930. X/* column widths, etc.                   */
  1931. X/*****************************************/
  1932. X
  1933. Xint
  1934. Xget_header_info(bufp,graphs,hlines)
  1935. Xchar *bufp;
  1936. Xshort *graphs, *hlines;
  1937. X{
  1938. X    int  i, j, count = -1;
  1939. X    char c;
  1940. X
  1941. X    *bufp = '\0';
  1942. X    *graphs = 0;
  1943. X    while (getline(bufp,MAXINRECLEN,infile) != EOF) {
  1944. X    j = trim(bufp);
  1945. X    if ('E' == toupper(*bufp))
  1946. X        ++(*graphs);
  1947. X      }
  1948. X    rewind(infile);
  1949. X    return(0);
  1950. X}
  1951. X
  1952. X
  1953. X/*****************************************/
  1954. X/* create and output a lotus label       */
  1955. X/*****************************************/
  1956. X
  1957. Xint
  1958. Xcreate_lotus_label(label,lcol,lrow)
  1959. Xchar *label;
  1960. Xshort lcol;
  1961. Xshort lrow;
  1962. X{
  1963. X    int i,j;
  1964. X    short c1, r1;
  1965. X    char *p;
  1966. X
  1967. X    p = (char *)(&LABELr);
  1968. X    int2s(swapb(lcol),LABELr.column);
  1969. X    int2s(swapb(lrow),LABELr.row);
  1970. X    *LABELr.string = '\0';
  1971. X    strcat(LABELr.string,label);
  1972. X/* fprintf(stderr,"x: %s\n",LABELr.string); */
  1973. X    int2s(swapb((unsigned short)(strlen(LABELr.string) + 7)),
  1974. X                    LABELr.record_length);
  1975. X    output_lotus_record(p);
  1976. X    return(0);
  1977. X}
  1978. X
  1979. X/*****************************************/
  1980. X/* create and output a lotus number      */
  1981. X/*****************************************/
  1982. X
  1983. Xint
  1984. Xcreate_lotus_number(number,ncol,nrow,ndp)
  1985. Xdouble number;
  1986. Xshort ncol;
  1987. Xshort nrow;
  1988. Xshort ndp;
  1989. X{
  1990. X    int i,j;
  1991. X    short c1, r1;
  1992. X    char *p;
  1993. X
  1994. X    p = (char *)(&NUMBERr);
  1995. X    int2s(swapb(ncol),NUMBERr.column);
  1996. X    int2s(swapb(nrow),NUMBERr.row);
  1997. X    *NUMBERr.format = (char)(0x80 + ndp);
  1998. X    stdbl(number,NUMBERr.value);
  1999. X    output_lotus_record(p);
  2000. X    return(0);
  2001. X}
  2002. X
  2003. X/*****************************************/
  2004. X/* output a lotus record -- note that    */
  2005. X/* the length of the record is contained */
  2006. X/* in the record itself (bytes 2-3)      */
  2007. X/* minus the 4 bytes of opcode+length    */
  2008. X/*****************************************/
  2009. X
  2010. Xint
  2011. Xoutput_lotus_record(record_pointer)
  2012. Xchar *record_pointer;
  2013. X{
  2014. X    int i, fstatus;
  2015. X    unsigned short total_length = 0;
  2016. X
  2017. X    total_length = swapb((unsigned short)s2int(record_pointer + 2)) + 4;
  2018. X
  2019. X    for (i = 0; i < total_length; i++)
  2020. X    fstatus = putc(*record_pointer++,outfile);
  2021. X
  2022. X    current_offset += (long)total_length;
  2023. X
  2024. X    return(fstatus);
  2025. X
  2026. X}
  2027. X
  2028. X/***********************************/
  2029. X/* our own getline -- like fgets,  */
  2030. X/* just returns null-term string   */
  2031. X/* instead of newline, and length  */
  2032. X/* instead of pointer              */
  2033. X/***********************************/
  2034. X
  2035. Xint
  2036. Xgetline(s,lim,stream)
  2037. Xchar s[];
  2038. Xint lim;
  2039. Xregister FILE *stream;
  2040. X{
  2041. X    int c, i;
  2042. X
  2043. X    i = 0;
  2044. X    while (--lim > 0 && (c = getc(stream)) != EOF && c != '\n')
  2045. X      s[i++] = c;
  2046. X
  2047. X    if (c == EOF)
  2048. X    return(c);
  2049. X
  2050. X    s[i] = '\0';
  2051. X/*    current_row++; */
  2052. X
  2053. X    return(i);
  2054. X
  2055. X}
  2056. X
  2057. Xint
  2058. Xstdbl(value,ptr)
  2059. Xdouble value;
  2060. Xchar *ptr;
  2061. X{
  2062. X    int i = 7;
  2063. X    char *dp;
  2064. X
  2065. X    dp = (char *)&value;
  2066. X    while (i > -1)
  2067. X    *ptr++ = *(dp + (i--));
  2068. X}
  2069. X
  2070. X/*****************************************/
  2071. X/* return a new string, with the first   */
  2072. X/* character non-whitespace.  Look out;  */
  2073. X/* it does clobber the passed contents,  */
  2074. X/* but returns the length of the result .*/
  2075. X/*****************************************/
  2076. X
  2077. Xint
  2078. Xtrim(p)
  2079. Xregister char *p;
  2080. X{
  2081. X    char *hp, *np;
  2082. X
  2083. X    if (*p != ' ' && *p != '\t')
  2084. X    return(strlen(p));
  2085. X
  2086. X    hp = np = p;
  2087. X
  2088. X    while(*p && (*p == ' ' || *p == '\t'))
  2089. X    p++;
  2090. X    while (*p)
  2091. X    *np++ = *p++;
  2092. X
  2093. X    *np = '\0';
  2094. X    return((int)(np - hp));
  2095. X}
  2096. X
  2097. X/*****************************************/
  2098. X/* fix a string, with the double quotes  */
  2099. X/* removed, and to a maximum length (not */
  2100. X/* including eos) NOTE: this routine     */
  2101. X/* may alter 'instr'.                    */
  2102. X/*****************************************/
  2103. X
  2104. Xchar *
  2105. Xqtstr(instr,outstr,maxlen)
  2106. Xchar *instr;
  2107. Xchar *outstr;
  2108. Xint  maxlen;
  2109. X{
  2110. X    int i, q;
  2111. X    char *isp, *osp;
  2112. X
  2113. X    q = 0;
  2114. X    i = trim(instr); /* it may be altered right here */
  2115. X    isp = instr;
  2116. X    osp = outstr;
  2117. X    if (*isp == '"') {
  2118. X    ++isp;
  2119. X    q++;
  2120. X    }
  2121. X    for (i = 0; ((i < maxlen) && *isp && ((q && *isp != '"') || (!q && *isp != ' '))); i++)
  2122. X        *osp++ = *isp++;
  2123. X    *osp = '\0';
  2124. X
  2125. X    if (i >= maxlen)
  2126. X    while (*isp && *isp != ' ' && *isp != '\t' && *isp != '"')
  2127. X        isp++;
  2128. X    return(*isp ? ++isp : isp);
  2129. X}
  2130. X
  2131. X/**********************************************************************/
  2132. X/* create a lotus formula range...lotus cell addresses are of two     */
  2133. X/* types, absolute and relative.  Absolute address place 0,0 at the   *
  2134. X/* upper left corner of the spreadsheet.  Relative address are        */
  2135. X/* "circular" relative, and are all negative.  The current cell is    */
  2136. X/* address -32768 (the maximum 16-bit signed negative).  The cell     */
  2137. X/* position immediately "above" or "left" of the current cell is      */
  2138. X/* -1, decreasing as you "decrease" your position.  The cell position */
  2139. X/* immediately "below" or "right" of the current cell is -32767,      */
  2140. X/* increasing as you "increase" your position.                        */
  2141. X/*                                                                    */
  2142. X/* c_col ("current" column) and c_row ("current" row) are actually    */
  2143. X/* just relative starting points for the addresses that follow them.  */
  2144. X/* The "type" parameter is simply a flag to indicate whether the      */
  2145. X/* range is a true range, all four parameters (type = 1), or whether  */
  2146. X/* it is just a column position (type = 0).  In the latter case, only */
  2147. X/* the start column and start row are done.                           */
  2148. X/*                                                                    */
  2149. X/* Oh, by the way;  don't forget to byte-swap each 16-bits if your    */
  2150. X/* computer is a big-endian!                                          */
  2151. X/**********************************************************************/
  2152. X
  2153. Xint
  2154. Xcreate_formula_range(range_ptr,c_col,c_row,s_col,s_row,e_col,e_row,type)
  2155. Xchar *range_ptr;
  2156. Xshort c_col, c_row, s_col, s_row, e_col, e_row;
  2157. Xint type;
  2158. X{
  2159. X    short rel_ptr;
  2160. X    char *p;
  2161. X
  2162. X    p = range_ptr;
  2163. X
  2164. X    rel_ptr = (s_col < c_col) ? (s_col - c_col - 8192) : (s_col - c_col - 32768);
  2165. X    int2s(swapb((unsigned short)rel_ptr),p);
  2166. X    p += 2;
  2167. X    rel_ptr = (s_row < c_row) ? (s_row - c_row - 8192) : (s_row - c_row - 32768);
  2168. X    int2s(swapb((unsigned short)rel_ptr),p);
  2169. X    if (type) {
  2170. X    p += 2;
  2171. X    rel_ptr = (e_col < c_col) ? (e_col - c_col - 8192) : (e_col - c_col - 32768);
  2172. X    int2s(swapb((unsigned short)rel_ptr),p);
  2173. X    p += 2;
  2174. X    rel_ptr = (e_row < c_row) ? (e_row - c_row - 8192) : (e_row - c_row - 32768);
  2175. X    int2s(swapb((unsigned short)rel_ptr),p);
  2176. X    }
  2177. X
  2178. X    return(0);
  2179. X
  2180. X}
  2181. X
  2182. X
  2183. X/**********************************************/
  2184. X/* Routine to count number of decimal places  */
  2185. X/* assumes that numbuf is already "trimmed"   */
  2186. X/* (i.e., no leading white space).            */
  2187. X/**********************************************/
  2188. X
  2189. Xshort
  2190. Xdecimals(numbuf)
  2191. Xchar    *numbuf;
  2192. X{
  2193. X    char *c, *p;
  2194. X
  2195. X    if ((p = strchr(numbuf,'.')) == NULL)
  2196. X        return((short)0);
  2197. X
  2198. X    c = ++p;
  2199. X    while (*c && isdigit(*c))
  2200. X        c++;
  2201. X
  2202. X    return((short)(c - p));
  2203. X}
  2204. END_OF_FILE
  2205. if test 29598 -ne `wc -c <'grph123.c'`; then
  2206.     echo shar: \"'grph123.c'\" unpacked with wrong size!
  2207. fi
  2208. # end of 'grph123.c'
  2209. fi
  2210. echo shar: End of archive 2 \(of 2\).
  2211. cp /dev/null ark2isdone
  2212. MISSING=""
  2213. for I in 1 2 ; do
  2214.     if test ! -f ark${I}isdone ; then
  2215.     MISSING="${MISSING} ${I}"
  2216.     fi
  2217. done
  2218. if test "${MISSING}" = "" ; then
  2219.     echo You have unpacked both archives.
  2220.     rm -f ark[1-9]isdone
  2221. else
  2222.     echo You still need to unpack the following archives:
  2223.     echo "        " ${MISSING}
  2224. fi
  2225. ##  End of shell archive.
  2226. exit 0
  2227.