1 /* 2 * Copyright (c) 1984-1987 by the Regents of the 3 * University of California and by Gregory Glenn Minshall. 4 * 5 * Permission to use, copy, modify, and distribute these 6 * programs and their documentation for any purpose and 7 * without fee is hereby granted, provided that this 8 * copyright and permission appear on all copies and 9 * supporting documentation, the name of the Regents of 10 * the University of California not be used in advertising 11 * or publicity pertaining to distribution of the programs 12 * without specific prior permission, and notice be given in 13 * supporting documentation that copying and distribution is 14 * by permission of the Regents of the University of California 15 * and by Gregory Glenn Minshall. Neither the Regents of the 16 * University of California nor Gregory Glenn Minshall make 17 * representations about the suitability of this software 18 * for any purpose. It is provided "as is" without 19 * express or implied warranty. 20 */ 21 22 #ifndef lint 23 static char sccsid[] = "@(#)api.c 3.1 (Berkeley) 08/11/87"; 24 #endif /* not lint */ 25 26 /* 27 * This file implements the API used in the PC version. 28 */ 29 30 #include <stdio.h> 31 32 #include "api.h" 33 #include "../general/general.h" 34 35 #include "../api/disp_asc.h" 36 37 #include "screen.h" 38 #include "oia.h" 39 40 #include "../general/globals.h" 41 42 /* 43 * General utility routines. 44 */ 45 46 #if defined(MSDOS) 47 48 #if defined(LINT_ARGS) 49 static void movetous(char *, int, int, int); 50 static void movetothem(int, int, char *, int); 51 #endif /* defined(LINT_ARGS) */ 52 53 #define access_api(foo,length,copyin) (foo) 54 #define unaccess_api(foo,goo,length,copyout) 55 56 static void 57 movetous(parms, es, di, length) 58 char *parms; 59 int es, di, length; 60 { 61 char far *farparms = parms; 62 63 movedata(es, di, (int) FP_SEG(farparms), (int) FP_OFF(farparms), length); 64 } 65 66 static void 67 movetothem(es, di, parms, length) 68 int es, di; 69 char *parms; 70 int length; 71 { 72 char far *farparms = parms; 73 74 movedata((int) FP_SEG(farparms), (int) FP_OFF(farparms), es, di, length); 75 } 76 #endif /* defined(MSDOS) */ 77 78 #if defined(unix) 79 extern char *access_api(), *unaccess_api(); 80 #endif /* defined(unix) */ 81 82 83 /* 84 * Supervisor Services. 85 */ 86 87 static void 88 name_resolution(regs, sregs) 89 union REGS *regs; 90 struct SREGS *sregs; 91 { 92 NameResolveParms parms; 93 94 movetous((char *) &parms, sregs->es, regs->x.di, sizeof parms); 95 96 regs->h.cl = 0; 97 if (memcmp((char *)&parms, NAME_SESSMGR, sizeof parms.gate_name) == 0) { 98 regs->x.dx = GATE_SESSMGR; 99 } else if (memcmp((char *)&parms, NAME_KEYBOARD, 100 sizeof parms.gate_name) == 0) { 101 regs->x.dx = GATE_KEYBOARD; 102 } else if (memcmp((char *)&parms, NAME_COPY, sizeof parms.gate_name) == 0) { 103 regs->x.dx = GATE_COPY; 104 } else if (memcmp((char *)&parms, NAME_OIAM, sizeof parms.gate_name) == 0) { 105 regs->x.dx = GATE_OIAM; 106 } else { 107 regs->h.cl = 0x2e; /* Name not found */ 108 } 109 regs->h.ch = 0x12; 110 regs->h.bh = 7; 111 } 112 113 /* 114 * Session Information Services. 115 */ 116 117 static void 118 query_session_id(regs, sregs) 119 union REGS *regs; 120 struct SREGS *sregs; 121 { 122 QuerySessionIdParms parms; 123 124 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); 125 126 if ((parms.rc != 0) || (parms.function_id != 0)) { 127 parms.rc = 0x0c; 128 } else if (parms.option_code != 0x01) { 129 parms.rc = 0x0d; /* Invalid option code */ 130 } else if (parms.data_code != 0x45) { 131 parms.rc = 0x0b; 132 } else { 133 NameArray list; 134 NameArrayElement element; 135 136 movetous((char *)&list, FP_SEG(parms.name_array), 137 FP_OFF(parms.name_array), sizeof list); 138 if ((list.length < 14) || (list.length > 170)) { 139 parms.rc = 0x12; 140 } else { 141 list.number_matching_session = 1; 142 list.name_array_element.short_name = parms.data_code; 143 list.name_array_element.type = TYPE_DFT; 144 list.name_array_element.session_id = 23; 145 memcpy(list.name_array_element.long_name, "ONLYSESS", 146 sizeof list.name_array_element.long_name); 147 movetothem(FP_SEG(parms.name_array), 148 FP_OFF(parms.name_array), (char *)&list, sizeof list); 149 parms.rc = 0; 150 } 151 } 152 parms.function_id = 0x6b; 153 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); 154 } 155 156 static void 157 query_session_parameters(regs, sregs) 158 union REGS *regs; 159 struct SREGS *sregs; 160 { 161 QuerySessionParametersParms parms; 162 163 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); 164 165 if ((parms.rc !=0) || (parms.function_id != 0)) { 166 parms.rc = 0x0c; 167 } else if (parms.session_id != 23) { 168 parms.rc = 0x02; 169 } else { 170 parms.rc = 0; 171 parms.session_type = TYPE_DFT; 172 parms.session_characteristics = 0; /* Neither EAB nor PSS */ 173 parms.rows = MaxNumberLines; 174 parms.columns = MaxNumberColumns; 175 parms.presentation_space = 0; 176 } 177 parms.function_id = 0x6b; 178 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); 179 } 180 181 static void 182 query_session_cursor(regs, sregs) 183 union REGS *regs; 184 struct SREGS *sregs; 185 { 186 QuerySessionCursorParms parms; 187 188 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); 189 190 if ((parms.rc != 0) || (parms.function_id != 0)) { 191 parms.rc = 0x0c; 192 } else if (parms.session_id != 23) { 193 parms.rc = 0x02; 194 } else { 195 parms.rc = 0; 196 parms.cursor_type = CURSOR_BLINKING; /* XXX what is inhibited? */ 197 parms.row_address = ScreenLine(CursorAddress); 198 parms.column_address = ScreenLineOffset(CursorAddress); 199 } 200 201 parms.function_id = 0x6b; 202 movetothem(sregs->es, regs->x.di, (char *) &parms, sizeof parms); 203 } 204 205 /* 206 * Keyboard Services. 207 */ 208 209 210 static void 211 connect_to_keyboard(regs, sregs) 212 union REGS *regs; 213 struct SREGS *sregs; 214 { 215 ConnectToKeyboardParms parms; 216 217 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); 218 219 if ((parms.rc != 0) || (parms.function_id != 0)) { 220 parms.rc = 0x0c; 221 } else if (parms.session_id != 23) { 222 parms.rc = 0x02; 223 } else if (parms.intercept_options != 0) { 224 parms.rc = 0x01; 225 } else { 226 parms.rc = 0; 227 parms.first_connection_identifier = 0; 228 } 229 parms.function_id = 0x62; 230 231 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); 232 } 233 234 static void 235 disconnect_from_keyboard(regs, sregs) 236 union REGS *regs; 237 struct SREGS *sregs; 238 { 239 DisconnectFromKeyboardParms parms; 240 241 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); 242 243 if ((parms.rc != 0) || (parms.function_id != 0)) { 244 parms.rc = 0x0c; 245 } else if (parms.session_id != 23) { 246 parms.rc = 0x02; 247 } else if (parms.connectors_task_id != 0) { 248 parms.rc = 04; /* XXX */ 249 } else { 250 parms.rc = 0; 251 } 252 parms.function_id = 0x62; 253 254 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); 255 } 256 257 static void 258 write_keystroke(regs, sregs) 259 union REGS *regs; 260 struct SREGS *sregs; 261 { 262 WriteKeystrokeParms parms; 263 264 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); 265 266 if ((parms.rc != 0) || (parms.function_id != 0)) { 267 parms.rc = 0x0c; 268 } else if (parms.session_id != 23) { 269 parms.rc = 0x02; 270 } else if (parms.connectors_task_id != 0) { 271 parms.rc = 0x04; 272 } else { 273 parms.number_of_keys_sent = 0; 274 parms.rc = 0; 275 if (parms.options == OPTION_SINGLE_KEYSTROKE) { 276 KeystrokeEntry *entry = &parms.keystroke_specifier.keystroke_entry; 277 278 if (AcceptKeystroke(entry->scancode, entry->shift_state) == 0) { 279 parms.rc = 0x10; /* XXX needs 0x12 too! */ 280 } 281 parms.number_of_keys_sent++; 282 } else if (parms.options == OPTION_MULTIPLE_KEYSTROKES) { 283 KeystrokeList 284 list, 285 far *atlist = parms.keystroke_specifier.keystroke_list; 286 KeystrokeEntry 287 entry[10], /* 10 at a time */ 288 *ourentry, 289 far *theirentry; 290 int 291 todo; 292 293 movetous((char *)&list, FP_SEG(atlist), 294 FP_OFF(atlist), sizeof *atlist); 295 todo = list.length/2; 296 ourentry = entry+(highestof(entry)+1); 297 298 while (todo) { 299 if (ourentry > &entry[highestof(entry)]) { 300 int thistime; 301 302 thistime = todo; 303 if (thistime > numberof(entry)) { 304 thistime = numberof(entry); 305 } 306 movetous((char *)entry, FP_SEG(theirentry), 307 FP_OFF(theirentry), thistime*sizeof *theirentry); 308 theirentry += thistime; 309 ourentry = entry; 310 } 311 if (AcceptKeystroke(ourentry->scancode, 312 ourentry->shift_state) == 0) { 313 parms.rc = 0x10; /* XXX needs 0x12 too! */ 314 break; 315 } 316 parms.number_of_keys_sent++; 317 ourentry++; 318 todo--; 319 } 320 } else { 321 parms.rc = 0x01; 322 } 323 } 324 parms.function_id = 0x62; 325 326 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); 327 /* XXX */ 328 } 329 330 331 static void 332 disable_input(regs, sregs) 333 union REGS *regs; 334 struct SREGS *sregs; 335 { 336 DisableInputParms parms; 337 338 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); 339 340 if ((parms.rc != 0) || (parms.function_id != 0)) { 341 parms.rc = 0x0c; 342 } else if (parms.session_id != 23) { 343 parms.rc = 0x02; 344 } else if (parms.connectors_task_id != 0) { 345 parms.rc = 0x04; 346 } else { 347 SetOiaApiInhibit(&OperatorInformationArea); 348 parms.rc = 0; 349 } 350 parms.function_id = 0x62; 351 352 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); 353 } 354 355 static void 356 enable_input(regs, sregs) 357 union REGS *regs; 358 struct SREGS *sregs; 359 { 360 EnableInputParms parms; 361 362 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); 363 364 if ((parms.rc != 0) || (parms.function_id != 0)) { 365 parms.rc = 0x0c; 366 } else if (parms.session_id != 23) { 367 parms.rc = 0x02; 368 } else if (parms.connectors_task_id != 0) { 369 parms.rc = 0x04; 370 } else { 371 ResetOiaApiInhibit(&OperatorInformationArea); 372 parms.rc = 0; 373 } 374 parms.function_id = 0x62; 375 376 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); 377 } 378 379 /* 380 * Copy Services. 381 */ 382 383 static 384 copy_subroutine(target, source, parms, what_is_user, length) 385 BufferDescriptor *target, *source; 386 CopyStringParms *parms; 387 int what_is_user; 388 #define USER_IS_TARGET 0 389 #define USER_IS_SOURCE 1 390 { 391 #define TARGET_NO_EAB 1 392 #define SOURCE_NO_EAB 2 393 #define TARGET_PC 4 394 #define SOURCE_PC 8 395 #define NO_FIELD_ATTRIBUTES 16 396 int needtodo = 0; 397 int access_length; 398 char far *input; 399 char far *output; 400 char far *access_pointer; 401 402 if ((target->characteristics^source->characteristics) 403 &CHARACTERISTIC_EAB) { 404 if (target->characteristics&CHARACTERISTIC_EAB) { 405 needtodo |= TARGET_NO_EAB; /* Need to bump for EAB in target */ 406 } else { 407 needtodo |= SOURCE_NO_EAB; /* Need to bump for EAB in source */ 408 } 409 } 410 if (target->session_type != source->session_type) { 411 if (target->session_type == TYPE_PC) { 412 needtodo |= TARGET_PC; /* scan codes to PC */ 413 } else { 414 needtodo |= SOURCE_PC; /* PC to scan codes */ 415 } 416 } 417 if ((parms->copy_mode©_MODE_FIELD_ATTRIBUTES) == 0) { 418 needtodo |= NO_FIELD_ATTRIBUTES; 419 } 420 access_length = length; 421 if (what_is_user == USER_IS_TARGET) { 422 if (target->characteristics&CHARACTERISTIC_EAB) { 423 access_length *= 2; 424 } 425 input = (char far *) &Host[source->begin]; 426 access_pointer = target->buffer; 427 output = access_api(target->buffer, access_length, 0); 428 } else { 429 if (source->characteristics&CHARACTERISTIC_EAB) { 430 access_length *= 2; 431 } 432 access_pointer = source->buffer; 433 input = access_api(source->buffer, access_length, 1); 434 output = (char far *) &Host[target->begin]; 435 } 436 while (length--) { 437 if (needtodo&TARGET_PC) { 438 *output++ = disp_asc[*input++]; 439 } else if (needtodo&SOURCE_PC) { 440 *output++ = asc_disp[*input++]; 441 } else { 442 *output++ = *input++; 443 } 444 if (needtodo&TARGET_NO_EAB) { 445 *input++; 446 } else if (needtodo&SOURCE_NO_EAB) { 447 *output++ = 0; /* Should figure out good EAB? */ 448 } 449 } 450 if (what_is_user == USER_IS_TARGET) { 451 unaccess_api(target->buffer, access_pointer, access_length, 1); 452 } else { 453 unaccess_api(source->buffer, access_pointer, access_length, 0); 454 } 455 } 456 457 458 static void 459 copy_string(regs, sregs) 460 union REGS *regs; 461 struct SREGS *sregs; 462 { 463 CopyStringParms parms; 464 BufferDescriptor *target = &parms.target, *source = &parms.source; 465 int length; 466 467 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); 468 469 length = 1+parms.source_end-source->begin; 470 if ((parms.rc != 0) || (parms.function_id !=0)) { 471 parms.rc = 0x0c; 472 } else if (target->session_id == 0) { /* Target is buffer */ 473 if (source->session_id != 23) { /* A no-no */ 474 parms.rc = 0x2; 475 } else { 476 if ((source->begin < 0) || (source->begin > highestof(Host))) { 477 parms.rc = 0x06; /* invalid source definition */ 478 } else { 479 if ((source->begin+length) > highestof(Host)) { 480 length = highestof(Host)-source->begin; 481 parms.rc = 0x0f; /* Truncate */ 482 } 483 if ((source->characteristics == target->characteristics) && 484 (source->session_type == target->session_type)) { 485 if (source->characteristics&CHARACTERISTIC_EAB) { 486 length *= 2; 487 } 488 movetothem( (int) FP_SEG(target->buffer), 489 (int) FP_OFF(target->buffer), 490 (char *)&Host[source->begin], length); 491 } else { 492 copy_subroutine(target, source, &parms, 493 USER_IS_TARGET, length); 494 } 495 } 496 } 497 } else if (source->session_id != 0) { 498 parms.rc = 0xd; 499 } else { 500 if ((target->begin < 0) || (source->begin > highestof(Host))) { 501 parms.rc = 0x07; /* invalid source definition */ 502 } else { 503 if ((source->begin+length) > highestof(Host)) { 504 length = highestof(Host)-source->begin; 505 parms.rc = 0x0f; /* Truncate */ 506 } 507 if ((source->characteristics == target->characteristics) && 508 (source->session_type == target->session_type)) { 509 if (source->characteristics&CHARACTERISTIC_EAB) { 510 length *= 2; 511 } 512 movetous((char *)&Host[target->begin], 513 (int) FP_SEG(source->buffer), 514 (int) FP_OFF(source->buffer), length); 515 } else { 516 copy_subroutine(target, source, &parms, USER_IS_SOURCE, length); 517 } 518 } 519 } 520 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); 521 } 522 /* 523 * Operator Information Area Services. 524 */ 525 526 static void 527 read_oia_group(regs, sregs) 528 union REGS *regs; 529 struct SREGS *sregs; 530 { 531 ReadOiaGroupParms parms; 532 533 movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); 534 535 if ((parms.rc != 0) || (parms.function_id != 0)) { 536 parms.rc = 0x0c; 537 } else if (parms.session_id != 23) { 538 parms.rc = 0x02; 539 } else { 540 int group = parms.oia_group_number; 541 char *from; 542 int size; 543 544 if ((group != API_OIA_ALL_GROUPS) && 545 ((group > API_OIA_LAST_LEGAL_GROUP) || (group < 0))) { 546 } else { 547 if (group == API_OIA_ALL_GROUPS) { 548 size = API_OIA_BYTES_ALL_GROUPS; 549 from = (char *)&OperatorInformationArea; 550 } else if (group == API_OIA_INPUT_INHIBITED) { 551 size = sizeof OperatorInformationArea.input_inhibited; 552 from = (char *)&OperatorInformationArea.input_inhibited[0]; 553 } else { 554 size = 1; 555 from = ((char *)&OperatorInformationArea)+group; 556 } 557 movetothem(FP_SEG(parms.oia_buffer), FP_OFF(parms.oia_buffer), 558 from, size); 559 } 560 } 561 parms.function_id = 0x6d; 562 movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); 563 } 564 565 static void 566 unknown_op(regs, sregs) 567 union REGS *regs; 568 struct SREGS *sregs; 569 { 570 regs->h.ch = 0x12; 571 regs->h.cl = 0x05; 572 } 573 574 575 handle_api(regs, sregs) 576 union REGS *regs; 577 struct SREGS *sregs; 578 { 579 if (regs->h.ah == NAME_RESOLUTION) { 580 name_resolution(regs, sregs); 581 #if defined(unix) 582 } else if (regs->h.ah == PS_OR_OIA_MODIFIED) { 583 while ((oia_modified == 0) && (ps_modified == 0)) { 584 (void) Scheduler(1); 585 } 586 oia_modified = ps_modified = 0; 587 #endif /* defined(unix) */ 588 } else if (regs->h.ah != 0x09) { 589 regs->h.ch = 0x12; 590 regs->h.cl = 0x0f; /* XXX Invalid environmental access */ 591 } else if (regs->x.bx != 0x8020) { 592 regs->h.ch = 0x12; 593 regs->h.cl = 0x08; /* XXX Invalid wait specified */ 594 } else if (regs->h.ch != 0) { 595 regs->x.cx = 0x1206; /* XXX Invalid priority */ 596 } else { 597 switch (regs->x.dx) { 598 case GATE_SESSMGR: 599 switch (regs->h.al) { 600 case QUERY_SESSION_ID: 601 if (regs->h.cl != 0) { 602 regs->x.cx = 0x1206; 603 } else { 604 regs->x.cx = 0x1200; 605 query_session_id(regs, sregs); 606 } 607 break; 608 case QUERY_SESSION_PARAMETERS: 609 if (regs->h.cl != 0) { 610 regs->x.cx = 0x1206; 611 } else { 612 regs->x.cx = 0x1200; 613 query_session_parameters(regs, sregs); 614 } 615 break; 616 case QUERY_SESSION_CURSOR: 617 if (regs->h.cl != 0xff) { 618 regs->x.cx = 0x1206; 619 } else { 620 regs->x.cx = 0x1200; 621 query_session_cursor(regs, sregs); 622 } 623 break; 624 default: 625 unknown_op(regs, sregs); 626 break; 627 } 628 break; 629 case GATE_KEYBOARD: 630 if (regs->h.cl != 00) { 631 regs->x.cx = 0x1206; 632 } else { 633 regs->x.cx = 0x1200; 634 switch (regs->h.al) { 635 case CONNECT_TO_KEYBOARD: 636 connect_to_keyboard(regs, sregs); 637 break; 638 case DISABLE_INPUT: 639 disable_input(regs, sregs); 640 break; 641 case WRITE_KEYSTROKE: 642 write_keystroke(regs, sregs); 643 break; 644 case ENABLE_INPUT: 645 enable_input(regs, sregs); 646 break; 647 case DISCONNECT_FROM_KEYBOARD: 648 disconnect_from_keyboard(regs, sregs); 649 break; 650 default: 651 unknown_op(regs, sregs); 652 break; 653 } 654 } 655 break; 656 case GATE_COPY: 657 if (regs->h.cl != 0xff) { 658 regs->x.cx = 0x1206; 659 } else { 660 regs->x.cx = 0x1200; 661 switch (regs->h.al) { 662 case COPY_STRING: 663 copy_string(regs, sregs); 664 break; 665 default: 666 unknown_op(regs, sregs); 667 break; 668 } 669 } 670 break; 671 case GATE_OIAM: 672 if (regs->h.cl != 0xff) { 673 regs->x.cx = 0x1206; 674 } else { 675 regs->x.cx = 0x1200; 676 switch (regs->h.al) { 677 case READ_OIA_GROUP: 678 read_oia_group(regs, sregs); 679 break; 680 default: 681 unknown_op(regs, sregs); 682 break; 683 } 684 } 685 break; 686 default: 687 regs->h.ch = 0x12; 688 regs->h.cl = 0x34; /* Invalid GATE entry */ 689 break; 690 } 691 } 692 } 693