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