| 1 | /* @(#)main.c 1.2 %G% |
| 2 | * |
| 3 | * Copyright -C- 1982 Barry S. Roitblat |
| 4 | * |
| 5 | * |
| 6 | * This is the main routine for the gremlin picture editor. |
| 7 | */ |
| 8 | |
| 9 | |
| 10 | #include "gremlin.h" |
| 11 | #include "grem2.h" |
| 12 | #include <signal.h> |
| 13 | #include <sgtty.h> |
| 14 | #include <sys/types.h> |
| 15 | #include <sys/stat.h> |
| 16 | |
| 17 | /* imports from config.c */ |
| 18 | |
| 19 | extern char GMapFile[]; |
| 20 | |
| 21 | /* database imports */ |
| 22 | |
| 23 | extern ELT *DBInit(), *DBRead(); |
| 24 | extern POINT *PTInit(), *PTMakePoint(); |
| 25 | |
| 26 | /* imports from menu.c */ |
| 27 | |
| 28 | extern MNInterpretCursor(); |
| 29 | extern MNIcon(), MNInitMenu(), MNDisplayMenu(); |
| 30 | |
| 31 | /* graphics imports */ |
| 32 | extern GRInit(), GRClose(); |
| 33 | extern GRSetGrid(), GRDisplayGrid(), GRBlankGrid(); |
| 34 | extern GRDisableTablet(), GREnableTablet(); |
| 35 | extern GRSetMap(), GRsetwmask(); |
| 36 | extern artmode; |
| 37 | |
| 38 | /* imports from undodb.c */ |
| 39 | |
| 40 | extern UNForget(); |
| 41 | extern UNELT *unlist, *unback; |
| 42 | |
| 43 | /* imports from long.c */ |
| 44 | |
| 45 | extern char *Editfile; |
| 46 | extern CP(), LGCommand(); |
| 47 | extern LGQuit(); |
| 48 | |
| 49 | /* imports from short.c */ |
| 50 | |
| 51 | extern SHCommand(); |
| 52 | extern SHRedis(); |
| 53 | extern SHUpdate(); |
| 54 | |
| 55 | /* other */ |
| 56 | |
| 57 | extern char *FindAED(); |
| 58 | |
| 59 | /* Forward references within this file: */ |
| 60 | |
| 61 | extern OnStop(), OnCommand(); |
| 62 | |
| 63 | /* Imports from textio.c: */ |
| 64 | |
| 65 | extern TxInit(), TxRedisplay(), TxClose(), TxPutMsg(), TxMsgOK(); |
| 66 | extern TxLine(), TxPutString(); |
| 67 | extern char TxGetChar(); |
| 68 | extern short inline; |
| 69 | extern TxPutString(); |
| 70 | extern TXFIELD TAlign, TAdjust, TBrush, TFont, TGravity, TCSize; |
| 71 | extern TXFIELD TEdit, TJustmode; |
| 72 | |
| 73 | |
| 74 | /* Library routines: */ |
| 75 | |
| 76 | extern char *malloc(), *sprintf(), *strcat(), *strcpy(); |
| 77 | |
| 78 | #ifdef SIGTINT |
| 79 | static int lintrup = LINTRUP; /* Constant for local mode bit */ |
| 80 | #endif SIGTINT |
| 81 | |
| 82 | /* Declaration of Globals */ |
| 83 | |
| 84 | ELT *PICTURE, *cset, arhead; |
| 85 | int CBRUSH, CFONT, CSIZE, CJUST, Gridsize, Gridon, Orientation; |
| 86 | int Alignment, SEQ, Adjustment, GravityOn, Consume, CHANGED; |
| 87 | float PX, PY, Lastx, Lasty; |
| 88 | POINT *POINTLIST, *BACKPOINT, MENPOINT[NUSER]; |
| 89 | ELT *MEN[NUSER]; |
| 90 | char cmdbuf[400]; |
| 91 | int SEARCH = TRUE; |
| 92 | int jmodes = 16; |
| 93 | char *textpos[] = {"bl", "bc", "br", "cl", "cc", "cr", "tl", "tc", "tr", |
| 94 | "lb", "cb", "rb", "lc", "rc", "lt", "ct", "rt" }; |
| 95 | char *dispmode[] = {"BL", "BR", "CC", "XX", "XX", "XX", "XX", "XX", |
| 96 | "XX", "XX", "TL", "TC", "TR", "CL", "CR", "BC" }; |
| 97 | int textmode[] = { 0, 15, 1, 13, 2, 14, 10, 11, 12, |
| 98 | 0, 15, 1, 13, 14, 10, 11, 12 }; |
| 99 | |
| 100 | /* symbolic types, brushes, etc. */ |
| 101 | |
| 102 | char *lines[] = { "broken", "dashed", "dotted", |
| 103 | "medium", "narrow", "thick", NULL }; |
| 104 | int lnum[] = { 2, 4, 1, 6, 5, 3 }; |
| 105 | char types[] = { 'l', 'r', 'c', 'v', 'a', 'u', '\0' }; |
| 106 | char *fonts[] = { "Bold", "Italics", "Roman", "Special", |
| 107 | "bold", "italics", "roman", "special", NULL }; |
| 108 | int fnum[] = { 3, 2, 1, 4, 3, 2, 1, 4 }; |
| 109 | |
| 110 | error(s) |
| 111 | char *s; |
| 112 | /* |
| 113 | * This routine prints an error message and sets the Consume flag |
| 114 | * so that points are not cleared. |
| 115 | */ |
| 116 | { |
| 117 | putchar('\7'); |
| 118 | TxPutMsg(s); |
| 119 | Consume = FALSE; |
| 120 | } |
| 121 | |
| 122 | |
| 123 | main(argc, argv) |
| 124 | int argc; |
| 125 | char *argv[]; |
| 126 | { |
| 127 | FILE *fp, *POpen(), *fopen(),*grtty, *tablet, *map, *startup; |
| 128 | POINT *p1, pos; |
| 129 | int x1, y1, x2, y2, i, j; |
| 130 | int button, cux, cuy; |
| 131 | char colours[768], msg[50], sw, *arg, *file; |
| 132 | char *ptr, *display, *type, *getenv(), home[100]; |
| 133 | char *path = "."; |
| 134 | struct stat buf; |
| 135 | ino_t inode; |
| 136 | |
| 137 | display = FindAED(); |
| 138 | if (display == NULL) display = "/dev/null"; |
| 139 | Orientation = 1; |
| 140 | file = NULL; |
| 141 | |
| 142 | /* Parse the command line. */ |
| 143 | |
| 144 | argc -= 1; argv++; /* Skip program name. */ |
| 145 | while (argc > 0) |
| 146 | { |
| 147 | argc -= 1; |
| 148 | arg = *argv++; |
| 149 | if (arg[0] != '-') file = arg; |
| 150 | else |
| 151 | { |
| 152 | sw = *++arg; |
| 153 | switch (sw) |
| 154 | { |
| 155 | case 'g': |
| 156 | if (*++arg == '\0') |
| 157 | if (argc-- > 0) arg = *argv++; |
| 158 | if (argc < 0) error("usage: gremlin -g <display name>"); |
| 159 | display = arg; |
| 160 | if (*display != '/') display = strcat("/dev/", arg); |
| 161 | break; |
| 162 | case 'p': |
| 163 | if (*++arg == '\0') |
| 164 | if (argc-- > 0) arg = *argv++; |
| 165 | if (argc < 0) error("usage: gremlin -g <path>"); |
| 166 | path = arg; |
| 167 | SEARCH = TRUE; |
| 168 | break; |
| 169 | case 'h': |
| 170 | Orientation = 0; |
| 171 | break; |
| 172 | case 'v': |
| 173 | Orientation = 1; |
| 174 | break; |
| 175 | default: |
| 176 | (void) sprintf(msg, "unknown switch: %c", sw); |
| 177 | error(msg); |
| 178 | } |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | PSetPath(path); |
| 183 | map = fopen(GMapFile, "r"); |
| 184 | for (i=0; i<768; ++i) /* read in color map */ |
| 185 | { |
| 186 | (void) fscanf(map,"%o",&j); |
| 187 | colours[i] = j&0377; |
| 188 | }; |
| 189 | |
| 190 | /* Open the display, and call all of the initialization routines. |
| 191 | * Initialize all of the globals defined in this file. |
| 192 | */ |
| 193 | type = getenv("TERM"); |
| 194 | TxInit(type); |
| 195 | |
| 196 | /* Ignore quit signals, catch interrupts and stops. */ |
| 197 | |
| 198 | sigset(SIGINT, SIG_IGN); |
| 199 | sigset(SIGTSTP, OnStop); |
| 200 | sigset(SIGTTIN, OnStop); |
| 201 | sigset(SIGTTOU, OnStop); |
| 202 | |
| 203 | #ifdef SIGTINT |
| 204 | sigset(SIGTINT, OnCommand); |
| 205 | sighold(SIGTINT); |
| 206 | #endif SIGTINT |
| 207 | |
| 208 | grtty = fopen(display,"w"); |
| 209 | if (grtty == NULL) |
| 210 | { |
| 211 | error("couldn't open display"); |
| 212 | LGQuit(display); |
| 213 | }; |
| 214 | tablet = fopen(display,"r"); |
| 215 | if (tablet == NULL) tablet = fopen("/dev/null", "r"); |
| 216 | GRInit(grtty,0); |
| 217 | GRSetMap(colours); |
| 218 | |
| 219 | #ifdef SIGTINT |
| 220 | (void) ioctl(fileno(stdin), TIOCLBIS, (char *) &lintrup); |
| 221 | #endif SIGTINT |
| 222 | |
| 223 | TxRedisplay(); /* display text screen */ |
| 224 | |
| 225 | CBRUSH = 6; |
| 226 | CFONT = 1; |
| 227 | CSIZE = 1; |
| 228 | CJUST = 0; |
| 229 | Gridon = FALSE; |
| 230 | Adjustment = NOADJ; |
| 231 | Alignment = 4; |
| 232 | artmode = FALSE; |
| 233 | SEQ = 0; |
| 234 | GravityOn = FALSE; |
| 235 | CHANGED = FALSE; |
| 236 | POINTLIST = PTInit(); |
| 237 | BACKPOINT = PTInit(); |
| 238 | unlist = unback = nullun; |
| 239 | p1 = PTInit(); /* initialize arrowhead template */ |
| 240 | (void) PTMakePoint(0.0, 0.0, &p1); |
| 241 | (void) PTMakePoint(-5.0, 3.0, &p1); |
| 242 | (void) PTMakePoint(-3.0, 0.0, &p1); |
| 243 | (void) PTMakePoint(-5.0, -3.0, &p1); |
| 244 | (void) PTMakePoint(0.0, 0.0, &p1); |
| 245 | arhead.type = VECTOR; |
| 246 | arhead.ptlist = p1; |
| 247 | arhead.brushf = 0; /* brush filled in when used */ |
| 248 | arhead.size = 0; |
| 249 | arhead.textpt = malloc(1); |
| 250 | *(arhead.textpt) = '\0'; |
| 251 | |
| 252 | PICTURE = DBInit(); /* initialize picture databse */ |
| 253 | cset = DBInit(); /* and current set */ |
| 254 | for (i=0; i<4; ++i) /* and user symbols */ |
| 255 | MEN[i] = DBInit(); |
| 256 | Editfile = malloc(100); |
| 257 | if (file == NULL) |
| 258 | *Editfile = '\0'; |
| 259 | else |
| 260 | { |
| 261 | (void) strcpy(Editfile, file); |
| 262 | fp = POpen(Editfile, (char **) NULL, SEARCH); |
| 263 | if (fp == NULL) error("(creating new file)"); |
| 264 | else PICTURE = DBRead(Editfile,&Orientation, &pos); |
| 265 | } |
| 266 | unlist = unback = nullun; |
| 267 | TxPutString(&TEdit, Editfile); |
| 268 | TxPutMsg(" Gremlin - Version 2.3 (1982)"); |
| 269 | MNIcon(); |
| 270 | MNInitMenu(Orientation); /* Initialize Menu */ |
| 271 | SHUpdate(); /* Display menu and picture, if any */ |
| 272 | |
| 273 | if (Orientation == 0) /* initialize grid */ |
| 274 | { |
| 275 | x1 = y1 = 0; |
| 276 | x2 = 511; |
| 277 | y2 = 395; |
| 278 | } |
| 279 | else |
| 280 | { |
| 281 | x1 = 116; |
| 282 | y1 = 0; |
| 283 | x2 = 511; |
| 284 | y2 = 483; |
| 285 | }; |
| 286 | Gridsize = 16; |
| 287 | GRSetGrid(x1, y1, x2, y2, Gridsize); |
| 288 | |
| 289 | /* read start-up file */ |
| 290 | /* look in home directory */ |
| 291 | sprintf(home,"%s/.gremlinrc",getenv("HOME")); |
| 292 | startup = fopen(home, "r"); |
| 293 | if (startup != NULL) |
| 294 | { |
| 295 | fstat(startup, &buf); |
| 296 | inode = buf.st_ino; |
| 297 | ptr = fgets(cmdbuf, 400, startup); |
| 298 | while (ptr != NULL) |
| 299 | { |
| 300 | for (i=0; (cmdbuf[i] != '\n'); ++i) |
| 301 | if (i > 399) break; |
| 302 | cmdbuf[i] = '\0'; /* remove trailing carriage return */ |
| 303 | if (cmdbuf[0] == ':') LGCommand(&(cmdbuf[1])); |
| 304 | else SHCommand(&(cmdbuf[0])); |
| 305 | ptr = fgets(cmdbuf, 400, startup); |
| 306 | } /* end while */ |
| 307 | } /* end if startup */ |
| 308 | else inode = 0; |
| 309 | |
| 310 | /* look in current directory */ |
| 311 | startup = fopen(".gremlinrc", "r"); |
| 312 | if (startup != NULL) |
| 313 | { |
| 314 | fstat(startup, &buf); |
| 315 | if (buf.st_ino != inode) /* This isn't the same file as above */ |
| 316 | { |
| 317 | ptr = fgets(cmdbuf, 400, startup); |
| 318 | while (ptr != NULL) |
| 319 | { |
| 320 | for (i=0; (cmdbuf[i] != '\n'); ++i) |
| 321 | if (i > 399) break; |
| 322 | cmdbuf[i] = '\0'; /* remove trailing carriage return */ |
| 323 | if (cmdbuf[0] == ':') LGCommand(&(cmdbuf[1])); |
| 324 | else SHCommand(&(cmdbuf[0])); |
| 325 | ptr = fgets(cmdbuf, 400, startup); |
| 326 | } /* end while */ |
| 327 | } /* end if buf */ |
| 328 | } /* end if startup */ |
| 329 | |
| 330 | while ( TRUE ) /* Exits through the 'quit' command */ |
| 331 | { |
| 332 | Consume = TRUE; |
| 333 | UNForget(); |
| 334 | |
| 335 | #ifdef SIGTINT |
| 336 | GREnableTablet(); |
| 337 | /* Allow keyboard interrupts while waiting |
| 338 | * for cursor input. |
| 339 | */ |
| 340 | sigrelse(SIGTINT); |
| 341 | button = GRGetButton(tablet, &cux, &cuy); |
| 342 | /* Ignore keyboard interrupts while processing commands. |
| 343 | */ |
| 344 | sighold(SIGTINT); |
| 345 | GRDisableTablet(); |
| 346 | TxMsgOK(); |
| 347 | MNInterpretCursor(button, cux, cuy); |
| 348 | if (Consume) CP(); |
| 349 | #else SIGTINT |
| 350 | i = 1 << fileno(stdin); |
| 351 | GREnableTablet(); |
| 352 | i |= (1 << fileno(tablet)); |
| 353 | (void) select(20, &i, 0, 10000000); |
| 354 | if (i & (1 << fileno(stdin))) |
| 355 | { |
| 356 | TxMsgOK(); |
| 357 | OnCommand(); |
| 358 | } |
| 359 | else |
| 360 | { |
| 361 | if ((button = GRGetButton(tablet, &cux, &cuy)) != -4) |
| 362 | { |
| 363 | GRDisableTablet(); |
| 364 | TxMsgOK(); |
| 365 | MNInterpretCursor(button, cux, cuy); |
| 366 | if (Consume) CP(); |
| 367 | } |
| 368 | } |
| 369 | #endif SIGTINT |
| 370 | |
| 371 | } /* end while */ |
| 372 | |
| 373 | } /* end main */ |
| 374 | |
| 375 | |
| 376 | OnStop(signo) |
| 377 | int signo; |
| 378 | |
| 379 | /*----------------------------------------------------------------------------- |
| 380 | * This procedure handles stop signals. |
| 381 | * |
| 382 | * Results: None. |
| 383 | * |
| 384 | * Side Effects: |
| 385 | * The text display is reset, we wait to get restarted, then |
| 386 | * redisplay text. |
| 387 | *----------------------------------------------------------------------------- |
| 388 | */ |
| 389 | |
| 390 | { |
| 391 | TxClose(); |
| 392 | sigset(signo, SIG_DFL); |
| 393 | (void) kill(0, signo); |
| 394 | sigset(signo, OnStop); |
| 395 | SHRedis(); |
| 396 | } |
| 397 | |
| 398 | |
| 399 | OnCommand() |
| 400 | |
| 401 | /*----------------------------------------------------------------------------- |
| 402 | * This routine responds to interrupts from the command terminal and |
| 403 | * then processes commands as long as there is input. |
| 404 | * |
| 405 | * Results: None. |
| 406 | * |
| 407 | * Side Effects: |
| 408 | * Whatever is done by the commands. |
| 409 | *----------------------------------------------------------------------------- |
| 410 | */ |
| 411 | |
| 412 | { |
| 413 | |
| 414 | #ifdef SIGTINT |
| 415 | long charcount; |
| 416 | #else SIGTINT |
| 417 | int i; |
| 418 | #endif SIGTINT |
| 419 | |
| 420 | static char cmd, lastcmd; |
| 421 | int repeat; |
| 422 | |
| 423 | GRDisableTablet(); |
| 424 | |
| 425 | #ifdef SIGTINT |
| 426 | (void) ioctl(fileno(stdin), TIOCLBIC, (char *) &lintrup); |
| 427 | #endif SIGTINT |
| 428 | |
| 429 | |
| 430 | while (TRUE) |
| 431 | { |
| 432 | |
| 433 | /* If there is no more input, then reenable the signal and return */ |
| 434 | |
| 435 | |
| 436 | #ifdef SIGTINT |
| 437 | (void) ioctl(fileno(stdin), FIONREAD, (char *) &charcount); |
| 438 | if (charcount == 0) |
| 439 | { |
| 440 | GREnableTablet(); |
| 441 | (void) ioctl(fileno(stdin), TIOCLBIS, (char *) &lintrup); |
| 442 | return; |
| 443 | } |
| 444 | #else SIGTINT |
| 445 | i = 1 << fileno(stdin); |
| 446 | if (select(20, &i, 0, 0) <= 0) |
| 447 | { |
| 448 | GREnableTablet(); |
| 449 | return; |
| 450 | } |
| 451 | #endif SIGTINT |
| 452 | |
| 453 | |
| 454 | /* Read the command and call the long or short command routine */ |
| 455 | |
| 456 | cmd = TxGetChar(); |
| 457 | if (cmd == '.') |
| 458 | { |
| 459 | repeat = TRUE; |
| 460 | cmd = lastcmd; |
| 461 | } |
| 462 | else |
| 463 | { |
| 464 | repeat = FALSE; |
| 465 | lastcmd = cmd; |
| 466 | } |
| 467 | if (cmd == ':') |
| 468 | { |
| 469 | if (!repeat) TxGetLine(":",cmdbuf,400); |
| 470 | LGCommand(cmdbuf); |
| 471 | } |
| 472 | else |
| 473 | { |
| 474 | TxLine(inline); |
| 475 | if (cmd != '\') putchar(cmd); |
| 476 | (void) fflush(stdout); |
| 477 | SHCommand(&cmd); |
| 478 | } |
| 479 | TxLine(inline); |
| 480 | printf(" "); |
| 481 | TxLine(inline); |
| 482 | if (Consume) CP(); |
| 483 | Consume = TRUE; |
| 484 | UNForget(); |
| 485 | } |
| 486 | } |
| 487 | |