1 /* @(#)long1.c 1.2 04/18/83 2 * 3 * Copyright -C- 1982 Barry S. Roitblat 4 * 5 * 6 * This file contains routines to implement the long text commands 7 * of the gremlin PICTURE editor. 8 * 9 */ 10 11 #include "gremlin.h" 12 #include "grem2.h" 13 #include <ctype.h> 14 15 /* imports from config.c */ 16 17 extern char GMailCommand[]; 18 19 /* imports from graphics files */ 20 21 extern GRVector(), GRArc(), GRPutText(); 22 extern GRDisplayPoint(), GRDeletePoint(), GRBlankPoints(); 23 extern charxsize, charysize; 24 extern artmode; /* indication of point display size */ 25 26 /* imports from display.c */ 27 28 extern DISScreenAdd(), DISScreenErase(); 29 extern DISDisplaySet(), DISEraseSet(), DISClearSetDisplay(); 30 31 /* imports from database files */ 32 33 extern ELT *DBInit(), *DBCreateElt(), *DBRead(); 34 extern DBDelete(), DBSetGravitate(), DBGravitate(), DBClearElt(); 35 extern ELT *DBCopy(); 36 extern DBXform(), DBChangeBrush(); 37 extern DBAddSet(), DBClearSet(); 38 extern POINT *PTInit(), *PTMakePoint(); 39 extern PTDeletePoint(); 40 41 /* imports from undodb.c */ 42 43 extern UNELT *unlist, *unback; 44 extern UNRembMod(); 45 46 /* imports from short.c */ 47 48 extern SHUpdate(); 49 50 /* imports from menu.c */ 51 52 extern MNHighLt(), MNUnHighLt(); 53 extern MNInitMenu(); 54 extern HiMen[], HiFont[], HiBrush[], HiMode[]; 55 56 /* imports from textio.c */ 57 58 extern TxMsgOK(), TxPutString(); 59 extern TXFIELD TAlign, TAdjust, TBrush, TFont, TGravity, TCSize; 60 extern TXFIELD TEdit, TJustmode; 61 62 /* imports from c */ 63 64 extern char *malloc(); 65 extern char *strcpy(), *sprintf(); 66 67 /* imports from main.c */ 68 69 extern ELT *PICTURE; /* current PICTURE database */ 70 extern ELT *cset; /* current set database */ 71 extern CBRUSH, CSIZE, CFONT; /* current brush, size, font */ 72 extern CJUST; /* current text justification */ 73 extern Gridon; /* grid mode flag */ 74 extern Orientation; /* orientation of workspace */ 75 extern Alignment; /* point alignment indicator */ 76 extern float PX, PY; /* cursor coordinates */ 77 extern float Lastx, Lasty; /* previous cursor coordinates */ 78 extern SEQ; /* point sequence number */ 79 extern char *Editfile; /* current edit file */ 80 extern POINT *POINTLIST, *BACKPOINT;/* accumulated point list */ 81 extern Adjustment; /* point adjustment mode */ 82 extern GravityOn; /* gravity mode flag */ 83 extern Consume; /* point clear flag */ 84 extern CHANGED; /* PICTURE changed flag */ 85 extern ELT *MEN[]; /* pointers for user symbols */ 86 extern POINT MENPOINT[]; /* pointers used fo user symbols */ 87 extern cmdbuf[]; /* line buffer for commands */ 88 extern char *lines[], *fonts[]; /* line and character styles */ 89 extern int lnum[], fnum[]; 90 91 /* The following is available to the outside world */ 92 93 int bang; 94 95 96 /* The following are defined to allow creation of the command 97 * lookup table. 98 */ 99 100 extern LGAlign(), LGBrush(), LGClearPoints(), LGGripe(), LGLittlePoint(), 101 LGDeletePoint(), LGEdit(), LGFont(), LGIncludeSet(), LGSize(), LGSave(), 102 LGJust(), LGMenu(), LGPoint(), LGPath(), LGQuit(), LGRead(), LGHAdjust(), 103 LGMBrush(), LGMFont(), LGMSize(), LGMText(), LGMPoint(), LGMirror(), 104 LGOrient(), LGVAdjust(), LGText(), LGUndo(), LGWrite(), LGOpoint(), 105 LGShowPoints(); 106 107 /* The following two arrays define the long commands and the routines 108 * that process them. 109 */ 110 static char *lcmds[] = { 111 "align", 112 "brush", 113 "buffer", 114 "clearpoints", 115 "deletepoint", 116 "edit", 117 "font", 118 "gripe", 119 "hadjust", 120 "includeset", 121 "justificaion", 122 "littlepoint", 123 "mbrush", 124 "mfont", 125 "mirror", 126 "mpoint", 127 "msize", 128 "mtext", 129 "orient", 130 "path", 131 "point", 132 "quit", 133 "read", 134 "size", 135 "saveset", 136 "showpoints", 137 "text", 138 "undo", 139 "vadjust", 140 "write", 141 "zpoint", 142 NULL}; 143 static (*(lrtns[]))() = { 144 LGAlign, /* align */ 145 LGBrush, /* set brush */ 146 LGMenu, /* select user set buffer */ 147 LGClearPoints, /* clear points */ 148 LGDeletePoint, /* delete a point */ 149 LGEdit, /* edit new file */ 150 LGFont, /* set font */ 151 LGGripe, /* leave a gripe or bug */ 152 LGHAdjust, /* horizontal adjust */ 153 LGIncludeSet, /* add to set */ 154 LGJust, /* text justification */ 155 LGLittlePoint, /* point size */ 156 LGMBrush, /* modify brush */ 157 LGMFont, /* modify font */ 158 LGMirror, /* mirror current set */ 159 LGMPoint, /* move point */ 160 LGMSize, /* modify size */ 161 LGMText, /* modify text string */ 162 LGOrient, /* change picture orientation */ 163 LGPath, /* set path or toggle search mode */ 164 LGOpoint, /* obtain point from terminal */ 165 LGQuit, /* quit */ 166 LGRead, /* read user sysmbol */ 167 LGSize, /* character size */ 168 LGSave, /* save current set in file */ 169 LGShowPoints, /* display reference points in set */ 170 LGText, /* input text */ 171 LGUndo, /* undo last command */ 172 LGVAdjust, /* vertical adjust */ 173 LGWrite, /* write file */ 174 LGPoint}; /* create point from cursor */ 175 176 177 int 178 LGLookup(str, table, next) 179 char str[]; /* Pointer to a string to be looked up */ 180 char *(table[]); /* Pointer to an array of string pointers 181 * which are the valid commands. The strings 182 * must be ordered monotonically (i.e. all 183 * strings whose first characters are identical 184 * must be adjacent in the table). 185 */ 186 int *next; 187 188 /*--------------------------------------------------------- 189 * LGLookup searches a table of strings to find one that matches a 190 * given string. 191 * 192 * Results: 193 * If str is an unambiguous abbreviation for one of the entries 194 * in table, then the index of the matching entry is returned. 195 * If str is an abbreviation for more than one entry in table, 196 * then -1 is returned. If str doesn't match any entry, then 197 * -2 is returned. 198 * 199 * Side Effects: None. 200 * 201 * (Modified from software written by John Ousterhout for the caesar 202 * program) 203 *--------------------------------------------------------- 204 */ 205 206 { 207 /* The search is carried out by using two pointers, one which moves 208 * forward through table from its start, and one which moves backward 209 * through table from its end. The two pointers mark the range of 210 * strings that match the portion of str that we have scanned. When 211 * all of the characters of str have been scanned, then the two 212 * pointers better be identical. 213 */ 214 char **bot, **top; 215 int match, index; 216 217 bang = FALSE; 218 match = 0; 219 bot = table; 220 for (top = table; *top != NULL; top++); 221 if (top == bot) return(-2); 222 top--; 223 224 for (index=0; ; index++) 225 { 226 *next = index; 227 228 /* Check for the end of string */ 229 230 if ( (str[index] == '\0') || 231 (str[index] == ',') || 232 (str[index] == ' ') ) 233 { 234 if (bot == top) return(match); 235 else return(-1); 236 } 237 if (str[index] == '!') bang = TRUE; 238 else 239 { 240 241 /* Move bot up until the string it points to matches str in the 242 * index'th position. Make match refer to the index of bot in table. 243 */ 244 while ((*bot)[index] != str[index]) 245 { 246 if (bot == top) return(-2); 247 bot++; 248 match++; 249 } 250 251 /* Move top down until it matches */ 252 while ((*top)[index] != str[index]) 253 { 254 if (bot == top) return(-2); 255 top--; 256 } 257 } 258 } 259 } 260 261 262 LGCommand(command) 263 char *command; 264 265 /*--------------------------------------------------------- 266 * This routine reads in, looks up, and executes a long command. 267 * 268 * Results: None. 269 * 270 * Side Effects: 271 * Depends on the command that is invoked. 272 *--------------------------------------------------------- 273 */ 274 275 { 276 int index, next; 277 278 if (*command == '\0') 279 { 280 Consume = FALSE; 281 return; 282 } 283 index = LGLookup(command, lcmds, &next); 284 if (index >= 0) 285 { 286 287 (*(lrtns[index]))(command + next); 288 } 289 else 290 { 291 if (index == -1) error("command is ambiguous."); 292 if (index == -2) error("not a command."); 293 } 294 } 295 296 static char badarg[10] = "bad args"; 297 static char noset[15] = "no current set"; 298 299 #define BADNUM -1 300 #define NONUM -2 301 #define Delimiter(c) ((c == '\0') || (c == ' ') || (c == ',')) 302 303 GetNumParm(line, index) 304 char *line; 305 int *index; 306 /* 307 * This routine trys to interpret the string starting at 308 * line+index as a positive integeral numeric parameter. The function 309 * returns the numeric equivalent or a negative number it there is some 310 * error in interpreting the string. 311 */ 312 313 { 314 char num[20]; 315 int i, result; 316 317 for (i=0; !Delimiter(*(line + *index)); ++i) 318 { 319 num[i] = *(line + *index); 320 if ( !isdigit(num[i]) ) return (BADNUM); 321 ++(*index); 322 } /* end for */ 323 if ( i == 0 ) return(NONUM); 324 num[i] = '\0'; 325 (void) sscanf(num,"%d",&result); 326 return(result); 327 } /* end GetNumParm */ 328 329 330 LGOpoint(line) 331 char *line; 332 /* 333 * This routine accepts coordinates from the text terminal 334 * and creates and displays a point from them by passing them 335 * along to LGPoint. 336 * 337 * NOTE: coordinates from the terminal must be non-negative 338 * integers. 339 */ 340 341 { 342 int index, xcoord, ycoord; 343 344 index = 1; 345 xcoord = GetNumParm(line, &index); 346 if (xcoord < 0) 347 { 348 error(badarg); 349 return; 350 } 351 ++index; 352 ycoord = GetNumParm(line, &index); 353 if (ycoord < 0) 354 { 355 error(badarg); 356 return; 357 } 358 PX = xcoord; 359 PY = ycoord; 360 LGPoint(line); 361 } /* end LGOpoint */ 362 363 364 LGPoint(line) 365 char *line; 366 /* 367 * This routine accepts cursor coordinates and creates and 368 * displays points according to the current adjustment and alignment 369 * modes. Note that alignment and gravity are mutually exclusive 370 * and adjustment takes precedence over either. 371 */ 372 373 { 374 ELT *temp; 375 POINT *p1; 376 377 temp = DBInit(); 378 if (GravityOn) DBGravitate (PX, PY, &PX, &PY, &p1, &temp, PICTURE); 379 if (DBNullelt(temp)) /* no gravity in effect */ 380 { 381 /* Round to nearest alignment boundary */ 382 383 PX = (float) (((int) (PX / Alignment + 0.5)) * Alignment); 384 PY = (float) (((int) (PY / Alignment + 0.5)) * Alignment); 385 } 386 387 388 if (SEQ > 0) /* this isn't the first point */ 389 { 390 if (Adjustment == HORZ) PY = Lasty; 391 if (Adjustment == VERT) PX = Lastx; 392 if (Adjustment == MAN) 393 if (fabs(PX - Lastx) > fabs(PY - Lasty)) PY = Lasty; 394 else PX = Lastx; 395 } /* end if SEQ */; 396 GRDisplayPoint((int) PX, (int) PY, SEQ, pointstyle); 397 (void) PTMakePoint(PX, PY, &POINTLIST); 398 Lastx = PX; 399 Lasty = PY; 400 Consume = FALSE; 401 ++SEQ; 402 } /* end Point */ 403 404 CP() 405 /* 406 * This routine deletes all points from the POINTLIST and 407 * clears them from the display also. 408 */ 409 410 { 411 POINT *temp; 412 413 while ( !Nullpoint(BACKPOINT) ) 414 { 415 temp = PTNextPoint(BACKPOINT); 416 free ((char *) BACKPOINT); 417 BACKPOINT = temp; 418 } 419 BACKPOINT = POINTLIST; 420 POINTLIST = PTInit(); 421 SEQ = 0; 422 GRBlankPoints(); 423 } /* end CP */ 424 425 426 LGClearPoints(line) 427 char *line; 428 /* 429 * This routine is a no-op since all points are cleared by default 430 * each time through the interpreter loop unless Consume is false. 431 */ 432 { 433 } 434 435 LGDeletePoint(line) 436 char *line; 437 /* 438 * This routine removes the last point from the POINTLIST 439 * and erases it from the screen. 440 */ 441 442 { 443 POINT *pt1, *pt2, *pt3; 444 float savex, savey; 445 int i; 446 447 if (SEQ == 0) 448 { 449 error("no point"); 450 return; 451 } 452 pt2 = pt3 = POINTLIST; 453 while ( !Nullpoint(pt3) ) /* find last point and pointer to it */ 454 { 455 pt1 = pt2; 456 pt2 = pt3; 457 pt3 = PTNextPoint(pt3); 458 }; 459 SEQ--; 460 savex = pt2->x; 461 savey = pt2->y; 462 GRErasePoint( (int) pt2->x, (int) pt2->y, SEQ); 463 PTDeletePoint(pt2); 464 if (SEQ > 0) /* any points left after deleting */ 465 { /* then pt1 points to last of them */ 466 Lastx = pt1->x; 467 Lasty = pt1->y; 468 pt3 = POINTLIST; /* redisplay any nearby points */ 469 for (i=0; i<SEQ; ++i) /* which may have been clobbered by */ 470 { /* the erase */ 471 if (fabs(pt3->x - savex) < (2*halfpoint)) 472 if (fabs(pt3->y - savey) < (2*halfpoint)) 473 GRDisplayPoint((int) pt3->x, 474 (int) pt3->y, 475 i, pointstyle); 476 pt3 = PTNextPoint(pt3); 477 } /* end for */ 478 } 479 Consume = FALSE; 480 } /* end DeletePoint */ 481 482 483 LGShowPoints(line) 484 char *line; 485 /* 486 * This routine causes the text elements in the current set 487 * to be redrawn using the new font. 488 */ 489 490 { 491 ELT *elist; 492 POINT *p1; 493 int pno; 494 495 if (DBNullelt(cset)) 496 { 497 error(noset); 498 return; 499 } 500 elist = cset; 501 while ( !DBNullelt(elist) ) 502 { 503 p1 = elist->ptlist; 504 pno = 0; 505 while (!Nullpoint(p1)) 506 { 507 GRDisplayPoint((int)p1->x, (int)p1->y, pno, pointstyle); 508 p1 = PTNextPoint(p1); 509 pno++; 510 } 511 elist = DBNextofSet(elist); 512 } /* end while */ 513 Consume = FALSE; 514 } /* end ShowPoints */ 515 516 517 LGText(line) 518 char *line; 519 /* This routine implements the text commands. It first looks 520 * for a justification specification (if not specified, default is 521 * centering), and then the text string from the input line. Text 522 * justification requires a point upon which the text is positioned. 523 */ 524 525 { 526 ELT *e1; 527 POINT pos, ppnt, *p1; 528 int i, j; 529 char *text; 530 531 if (SEQ == 0) 532 { 533 error("not enough points"); 534 return; 535 } 536 if (*line == '\0') return; /* no text */ 537 for (; *line == ' '; ++line) /* delete leading blanks */ 538 i = strlen(line); 539 text = malloc((unsigned) i + 1); 540 (void) strcpy(text, line); 541 DBClearSet(); /* clear old current set so this can form */ 542 DISClearSetDisplay(); /* the new one */ 543 GRsetwmask(textmask | setmask); 544 ppnt.x = POINTLIST->x; 545 ppnt.y = POINTLIST->y; 546 if (SEQ > 1) 547 { 548 p1 = PTNextPoint(POINTLIST); 549 ppnt.x = (POINTLIST->x + p1->x)/2; 550 ppnt.y = (POINTLIST->y + p1->y)/2; 551 } 552 553 GRPutText(CJUST, &ppnt, CFONT, CSIZE, text, &pos); 554 p1 = PTInit(); 555 (void) PTMakePoint(ppnt.x, ppnt.y, &p1); 556 /* end extra positioning points */ 557 (void) PTMakePoint(pos.x, pos.y, &p1); 558 (void) PTMakePoint(pos.x + i * charxsize / 2, pos.y, &p1); 559 (void) PTMakePoint(pos.x + i * charxsize, pos.y, &p1); 560 e1 = DBCreateElt(CJUST, p1, CFONT, CSIZE, text, &PICTURE); 561 DBAddSet(e1); 562 CHANGED = TRUE; 563 } /* end LGText */ 564 565 566 567 LGBrush(line) 568 char *line; 569 /* 570 * This routine sets the current brush to that specified in the 571 * parameter. 572 */ 573 574 { 575 int newbrush, index; 576 char string[2]; 577 578 index = 0; 579 if (isalpha(*(++line))) 580 { 581 newbrush = LGLookup(line, lines, &index); 582 if (newbrush >= 0) newbrush = lnum[newbrush]; 583 else newbrush = BADNUM; 584 } 585 else newbrush = GetNumParm(line, &index); 586 if ( (newbrush == BADNUM) || (newbrush > NBRUSHES) ) 587 { 588 error(badarg); 589 return; 590 } 591 MNUnHighLt(HiBrush[CBRUSH-1]); 592 MNHighLt(HiBrush[newbrush-1], hicolor); 593 CBRUSH = newbrush; 594 (void) sprintf(string,"%1d",newbrush); 595 TxPutString(&TBrush,string); 596 Consume = FALSE; 597 } /* end LGBrush */ 598 599 600 601 LGMBrush(line) 602 char *line; 603 /* 604 * This routine causes the elements in the current set 605 * to be redrawn using the new brush. 606 */ 607 608 { 609 ELT *elist; 610 int new, index; 611 612 index = 0; 613 if (isalpha(*(++line))) 614 { 615 new = LGLookup(line, lines, &index); 616 if (new >= 0) new = lnum[new]; 617 else new = BADNUM; 618 } 619 else new = GetNumParm(line, &index); 620 if ( (new < 0) || (new > NBRUSHES) ) 621 { 622 error(badarg); 623 return; 624 } 625 if (DBNullelt(cset)) 626 { 627 error(noset); 628 return; 629 } 630 elist = cset; 631 while ( !DBNullelt(elist) ) 632 { 633 if (!TEXT(elist->type)) 634 { 635 DISScreenErase(elist, (linemask | setmask)); 636 DBChangeBrush(elist, new, &PICTURE); 637 DISScreenAdd(elist, (linemask | setmask)); 638 } /* end if */ 639 elist = DBNextofSet(elist); 640 } /* end while */ 641 CHANGED = TRUE; 642 } /* end MBrush */ 643 644 645 LGMFont(line) 646 char *line; 647 /* 648 * This routine causes the text elements in the current set 649 * to be redrawn using the new font. 650 */ 651 652 { 653 ELT *elist; 654 int new, index; 655 656 index = 0; 657 if (isalpha(*(++line))) 658 { 659 new = LGLookup(line, fonts, &index); 660 if (new >= 0) new = fnum[new]; 661 else new = BADNUM; 662 } 663 else new = GetNumParm(line, &index); 664 if ( (new < 0) || (new > NFONTS) ) 665 { 666 error(badarg); 667 return; 668 } 669 if (DBNullelt(cset)) 670 { 671 error(noset); 672 return; 673 } 674 elist = cset; 675 while ( !DBNullelt(elist) ) 676 { 677 if (TEXT(elist->type)) 678 { 679 DISScreenErase(elist, (linemask | setmask)); 680 TxMsgOK(); 681 DBChangeFont(elist, new, elist->size, &PICTURE); 682 DISScreenAdd(elist, (linemask | setmask)); 683 } /* end if */ 684 elist = DBNextofSet(elist); 685 } /* end while */ 686 CHANGED = TRUE; 687 } /* end MFont */ 688 689 690 LGMSize(line) 691 char *line; 692 /* 693 * This routine causes the text elements in the current set 694 * to be redrawn using the new size. 695 * 696 */ 697 698 { 699 POINT *p1, *p2, pos; 700 ELT *elist; 701 int new, index, i, j; 702 703 index = 1; 704 new = GetNumParm(line, &index); 705 if ( (new < 0) || (new > NSIZES) ) 706 { 707 error(badarg); 708 return; 709 } 710 if (DBNullelt(cset)) 711 { 712 error(noset); 713 return; 714 } 715 elist = cset; 716 while ( !DBNullelt(elist) ) 717 { 718 if (TEXT(elist->type)) 719 { 720 DISScreenErase(elist, (linemask | setmask)); 721 TxMsgOK(); 722 UNRembMod(elist,&PICTURE); 723 elist->size = new; 724 GRsetwmask(textmask | setmask); 725 p1 = elist->ptlist; 726 GRPutText(elist->type, p1, elist->brushf, 727 elist->size,elist->textpt, &pos); 728 i= strlen(elist->textpt); 729 p2 = PTInit(); 730 (void) PTMakePoint(p1->x, p1->y, &p2); 731 /* end extra positioning points */ 732 (void) PTMakePoint(pos.x, pos.y, &p2); 733 (void) PTMakePoint(pos.x + i * charxsize / 2, 734 pos.y, &p2); 735 (void) PTMakePoint(pos.x + i * charxsize, pos.y, &p2); 736 elist->ptlist = p2; 737 } /* end if */ 738 elist = DBNextofSet(elist); 739 } /* end while */ 740 CHANGED = TRUE; 741 } /* end MSize */ 742 743 744 LGMText(line) 745 char *line; 746 /* This routine allows modification of text by replacing 747 * an existing string with a new one, appropriately repositioned 748 */ 749 750 { 751 ELT *e1; 752 POINT pos, ppnt, *p1; 753 int i, j; 754 char *text; 755 756 i = strlen(++line); 757 text = malloc((unsigned) i + 1); 758 (void) strcpy(text, line); 759 GRsetwmask(textmask | setmask); 760 e1 = cset; 761 while ( !DBNullelt(e1) ) 762 { 763 if (TEXT(e1->type)) 764 { 765 DISScreenErase(e1, (textmask | setmask)); 766 TxMsgOK(); 767 UNRembMod(e1, &PICTURE); 768 ppnt.x = e1->ptlist->x; 769 ppnt.y = e1->ptlist->y; 770 771 GRPutText(e1->type, &ppnt, e1->brushf, e1->size, text, &pos); 772 p1 = PTInit(); 773 (void) PTMakePoint(ppnt.x, ppnt.y, &p1); 774 /* end extra positioning points */ 775 (void) PTMakePoint(pos.x, pos.y, &p1); 776 (void) PTMakePoint(pos.x + i * charxsize / 2, pos.y, &p1); 777 (void) PTMakePoint(pos.x + i * charxsize, pos.y, &p1); 778 e1->textpt = text; 779 } /* end if text */ 780 e1 = DBNextofSet(e1); 781 } /* end while */ 782 CHANGED = TRUE; 783 } /* end LGMText */ 784 785 LGMPoint(line) 786 char *line; 787 /* 788 * This routine modifies the element which contains the point 789 * closest to the first of two specified points so that that point 790 * coincides with the second of the points (if specified). 791 * 792 * Note: it implies knowlege of the database representation by modifying 793 * the element directly. 794 */ 795 796 { 797 ELT *e1; 798 POINT *p1, *p2, *p3, *p4; 799 float x1, y1; 800 801 if (SEQ < 1) /* no points */ 802 { 803 error("no point specified"); 804 return; 805 } 806 /* find point */ 807 DBSetGravitate(POINTLIST->x, POINTLIST->y, &x1, &y1, &p1, &e1, cset); 808 if ( !DBNullelt(e1) ) 809 { 810 DBClearSet(); 811 DISClearSetDisplay(); 812 DISScreenErase(e1, (linemask | setmask)); 813 UNRembMod(e1,&PICTURE); 814 if (SEQ > 1) /* move a point, not delete */ 815 { 816 p2 = PTNextPoint(POINTLIST); 817 p1->x = p2->x; 818 p1->y = p2->y; 819 p2 = PTNextPoint(p2); 820 if (!Nullpoint(p2)) 821 { 822 p3 = PTInit(); 823 while (!Nullpoint(p2)) 824 { 825 p4 = PTMakePoint(p2->x, p2->y, &p3); 826 p2 = PTNextPoint(p2); 827 } 828 p4->nextpt = p1->nextpt; 829 p1->nextpt = p3; 830 } 831 } 832 else 833 { 834 PTDeletePoint(p1); 835 } 836 DISScreenAdd(e1, (linemask | setmask)); 837 DBAddSet(e1); 838 } /* end if !DBNullelt */ 839 } /* end MPOINT */ 840 841 842 LGGripe(line) 843 char *line; 844 /* 845 * This routine allows users to leave gripe messages or report 846 * bugs to the maintainer. Mail is invoked via the defined constant GRIPE. 847 */ 848 849 { 850 TxClose(); /* Restore text terminal to 'normal' state */ 851 (void) system(GMailCommand); /* mail complaint */ 852 SHRedis(); /* reclaim terminal */ 853 } /* end Gripe */ 854 855 LGLittlePoint(line) 856 char *line; 857 /* 858 * This routine controls the size of the point that is displayed 859 * The sizes available are artmode in which a small (3 x 3) point is displayed 860 * with no number and regular (non- artmode). 861 */ 862 863 { 864 865 if (artmode) artmode = FALSE; 866 else artmode = TRUE; 867 Consume = FALSE; 868 } /* end Little Point */ 869 870 871 SetOrient(orient) 872 int orient; 873 /* 874 * This routine sets up the orientation of the drawing area. 875 */ 876 877 { 878 int x1, x2, y1, y2; /* used to set grid parameters */ 879 880 if (orient == 0) /* initialize grid */ 881 { 882 x1 = y1 = 0; 883 x2 = 511; 884 y2 = 395; 885 } 886 else 887 { 888 x1 = 116; 889 y1 = 0; 890 x2 = 511; 891 y2 = 483; 892 }; 893 MNInitMenu(orient); 894 GRSetGrid(x1, y1, x2, y2, 16); 895 } 896 897 LGOrient(line) 898 char *line; 899 /* 900 * This routine toggles the orientation of the drawing area. 901 */ 902 903 { 904 905 if (Orientation == 1) 906 { 907 Orientation = 0; 908 } 909 else 910 { 911 Orientation = 1; 912 }; 913 SetOrient(Orientation); 914 SHUpdate(); 915 } /* end Orient */ 916 917 918 LGSave(line) 919 char *line; 920 /* 921 * This routine writes the current set into the specified filename 922 * or to the current Editfile 923 */ 924 925 { 926 FILE *fp, *fopen(); 927 char tname[50], filename[100], string[100], *tn, *fn, *wfile; 928 ELT *elist; 929 POINT *plist, pos; 930 int i, space, stat; 931 932 space = 100; 933 ++line; 934 tn = tname; fn = filename; 935 (void) sscanf(line, "%s", tname); 936 i = strlen(tname); 937 if (i == 0) /* no filename */ 938 { 939 error("write to where?"); 940 return; 941 } 942 stat = PConvertTilde(&tn, &fn, &space); 943 *fn = '\0'; 944 if (stat == FALSE) 945 { 946 sprintf(string, "unknown path %s", tname); 947 error(string); 948 return; 949 } 950 if ( !bang ) /* user doesn't insist */ 951 { 952 fp = fopen(filename, "r"); 953 if ( fp != NULL ) 954 { 955 error("file already exists"); 956 return; 957 } 958 } 959 fp = fopen(filename, "w"); 960 wfile = filename; 961 if (fp == NULL) /* file error */ 962 { 963 (void) sprintf(string,"can't open %s", wfile); 964 error(string); 965 return; 966 }; 967 TxPutMsg("writing file..."); 968 CHANGED = FALSE; 969 if (SEQ > 0) /* specified a positioning point */ 970 { 971 pos.x = POINTLIST->x; 972 pos.y = POINTLIST->y; 973 } 974 else 975 { 976 if ( !DBNullelt(PICTURE) ) 977 { 978 pos.x = PICTURE->ptlist->x; 979 pos.y = PICTURE->ptlist->y; 980 } 981 else 982 { 983 pos.x = pos.y = 0; 984 }; 985 } 986 fprintf(fp,"gremlinfile\n"); /* write header */ 987 fprintf(fp, "%d %1.2f %1.2f\n", Orientation, pos.x, pos.y); 988 elist = cset; 989 while ( !DBNullelt(elist) ) /* write each element */ 990 { 991 fprintf(fp, "%d\n", elist->type); 992 plist = elist->ptlist; 993 while ( !Nullpoint(plist) ) /* write each point */ 994 { 995 fprintf(fp, "%1.2f %1.2f\n",plist->x, plist->y); 996 plist = PTNextPoint(plist); 997 } /* end while plist */ 998 fprintf(fp, "%1.2f %1.2f\n", -1.0, -1.0); /* end pointlist */ 999 fprintf(fp, "%d %d\n",elist->brushf, elist->size); 1000 fprintf(fp,"%d %s\n ", strlen(elist->textpt), elist->textpt); 1001 elist = DBNextofSet(elist); 1002 } /* end while */ 1003 fprintf(fp,"%d\n",-1); /* end of element list */ 1004 TxMsgOK(); 1005 (void) fclose(fp); 1006 } /* end LGSave */; 1007