Parse a terminfo file. Populate the _capabilities dict for easy retrieval Based on ncurses implementation in: - ncurses/tinfo/read_entry.c:_nc_read_termtype() - ncurses/tinfo/read_entry.c:_nc_read_file_entry() - ncurses/tinfo/lib_ti.c:tigetstr()
(self, terminal_name: str)
| 355 | self._capabilities = _TERMINAL_CAPABILITIES[term_type].copy() |
| 356 | |
| 357 | def _parse_terminfo_file(self, terminal_name: str) -> None: |
| 358 | """Parse a terminfo file. |
| 359 | |
| 360 | Populate the _capabilities dict for easy retrieval |
| 361 | |
| 362 | Based on ncurses implementation in: |
| 363 | - ncurses/tinfo/read_entry.c:_nc_read_termtype() |
| 364 | - ncurses/tinfo/read_entry.c:_nc_read_file_entry() |
| 365 | - ncurses/tinfo/lib_ti.c:tigetstr() |
| 366 | """ |
| 367 | data = _read_terminfo_file(terminal_name) |
| 368 | too_short = f"TermInfo file for {terminal_name!r} too short" |
| 369 | offset = 12 |
| 370 | if len(data) < offset: |
| 371 | raise ValueError(too_short) |
| 372 | |
| 373 | magic, name_size, bool_count, num_count, str_count, str_size = ( |
| 374 | struct.unpack("<Hhhhhh", data[:offset]) |
| 375 | ) |
| 376 | |
| 377 | if magic == MAGIC16: |
| 378 | number_size = 2 |
| 379 | elif magic == MAGIC32: |
| 380 | number_size = 4 |
| 381 | else: |
| 382 | raise ValueError( |
| 383 | f"TermInfo file for {terminal_name!r} uses unknown magic" |
| 384 | ) |
| 385 | |
| 386 | # Skip data than PyREPL doesn't need: |
| 387 | # - names (`|`-separated ASCII strings) |
| 388 | # - boolean capabilities (bytes with value 0 or 1) |
| 389 | # - numbers (little-endian integers, `number_size` bytes each) |
| 390 | offset += name_size |
| 391 | offset += bool_count |
| 392 | if offset % 2: |
| 393 | # Align to even byte boundary for numbers |
| 394 | offset += 1 |
| 395 | offset += num_count * number_size |
| 396 | if offset > len(data): |
| 397 | raise ValueError(too_short) |
| 398 | |
| 399 | # Read string offsets |
| 400 | end_offset = offset + 2 * str_count |
| 401 | if offset > len(data): |
| 402 | raise ValueError(too_short) |
| 403 | string_offset_data = data[offset:end_offset] |
| 404 | string_offsets = [ |
| 405 | off for [off] in struct.iter_unpack("<h", string_offset_data) |
| 406 | ] |
| 407 | offset = end_offset |
| 408 | |
| 409 | # Read string table |
| 410 | if offset + str_size > len(data): |
| 411 | raise ValueError(too_short) |
| 412 | string_table = data[offset : offset + str_size] |
| 413 | |
| 414 | # Extract strings from string table |
no test coverage detected