├── .gitignore ├── CMakeLists.txt ├── README.md ├── build.sh ├── lib ├── OpenGLLibraryStub ├── OpenGLMemoryStub └── OpenGLUtilityStub └── src ├── console ├── Console.cpp ├── Console.hpp ├── ConsoleWindow.cpp ├── ConsoleWindow.hpp ├── InitConsole.cpp └── MacUtils.h ├── detection ├── 68kextras.cpp ├── battery.cpp ├── cpu.cpp ├── disk.cpp ├── functions.cpp ├── functions.hpp ├── gestalt.cpp ├── gpu.cpp ├── memory.cpp ├── misc.cpp ├── os.cpp ├── rom.cpp ├── user.cpp └── xpostcode │ ├── CPUDevice.cpp │ └── CPUDevice.h ├── logo.hpp └── os9fetch.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *build*/ 3 | *.bin 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(os9fetch LANGUAGES C CXX) 4 | 5 | 6 | # compile flags 7 | add_compile_options(${COMPILE_FLAGS}) 8 | add_compile_definitions( 9 | _GNU_SOURCE 10 | CONFIG_BIGNUM 11 | CONFIG_VERSION=${QUICKJS_VERSION} 12 | CONFIG_AGENT=0 13 | ) 14 | 15 | set(QJSC_CONFIG -DCONFIG_PREFIX="/usr/local" -DCONFIG_LTO) 16 | set(QJSC_EXE "${EXECUTABLE_OUTPUT_PATH}/qjsc") 17 | set(QJS_CONFIG ${QJSC_CONFIG} -DCONFIG_CC="clang") 18 | 19 | 20 | ############################################################################### 21 | ## file globbing ############################################################## 22 | ############################################################################### 23 | 24 | # these instructions search the directory tree when CMake is 25 | # invoked and put all files that match the pattern in the variables 26 | # `sources` and `data` 27 | file(GLOB_RECURSE sources 28 | src/**/**/**/*.c src/**/**/**/*.h src/**/**/**/*.cpp src/**/**/**/*.hpp 29 | src/**/**/*.c src/**/**/*.h src/**/**/*.cpp src/**/**/*.hpp 30 | src/**/*.c src/**/*.h src/**/*.cpp src/**/*.hpp 31 | src/*.c src/*.h src/*.cpp src/*.hpp 32 | ) 33 | file(GLOB_RECURSE data resources/*) 34 | # you can use set(sources src/main.cpp) etc if you don't want to 35 | # use globbing to find files automatically 36 | 37 | ############################################################################### 38 | ## target definitions ######################################################### 39 | ############################################################################### 40 | 41 | # add the data to the target, so it becomes visible in some IDE 42 | 43 | if(CMAKE_SYSTEM_NAME MATCHES Retro) 44 | add_application(os9fetch ${sources} ${data}) 45 | else() 46 | add_executable(os9fetch ${sources} ${data}) 47 | endif() 48 | target_link_directories(os9fetch PUBLIC ${CMAKE_SOURCE_DIR}/lib ) 49 | 50 | set_property(TARGET os9fetch PROPERTY CXX_STANDARD 20) 51 | 52 | # just for os9fetch add some compiler flags 53 | target_compile_options(os9fetch PUBLIC -std=c++20 -Wall -Wfloat-conversion) 54 | 55 | set_target_properties(os9fetch PROPERTIES COMPILE_OPTIONS -ffunction-sections) 56 | #target_link_libraries(os9fetch "${RETRO68_ROOT}/InterfaceAndLibraries/Libraries/StubLibraries/ThreadsLib") 57 | 58 | #target_link_libraries( os9fetch ThreadsLib) 59 | 60 | if(PLATFORM MATCHES retro68) 61 | add_compile_definitions(FOR_68K) 62 | endif() 63 | 64 | if(PLATFORM MATCHES retroppc) 65 | add_compile_definitions(FOR_PPC) 66 | set_target_properties(os9fetch PROPERTIES COMPILE_FLAGS "-ffunction-sections -mcpu=601 -O3 -Wall -Wextra -Wno-unused-parameter") 67 | set_target_properties(os9fetch PROPERTIES LINK_FLAGS "-Wl,-gc-sections") 68 | target_link_libraries( os9fetch PowerMgrLib) 69 | target_link_libraries( os9fetch NameRegistryLib) 70 | target_link_libraries( os9fetch OpenGL) 71 | endif() 72 | 73 | 74 | include_directories( "${RETRO68_TOOLCHAIN}universal/CIncludes/") 75 | message(STATUS "Making for ${CMAKE_SYSTEM_NAME}") 76 | if(CMAKE_SYSTEM_NAME MATCHES Retro68) 77 | set_target_properties(os9fetch PROPERTIES LINK_FLAGS "-Wl,--mac-strip-macsbug") 78 | endif() 79 | 80 | # this copies all resource files in the build directory 81 | # we need this, because we want to work with paths relative to the executable 82 | file(COPY ${data} DESTINATION resources) 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 12 | 13 |
4 | 5 | 6 | 8 |

PowerFetch

9 |

Neofetch clone for Classic Mac based computers, so that you can show off your Macs in the same endearingly stupid way that modern Linux users get to! It can be run going back to System 4.0, on both PowerPC and 68k!

10 |
14 | 15 | # Compiling 16 | 17 | Install [Retro68](https://github.com/autc04/Retro68), then set `$RETRO68_TOOLCHAIN_PATH` to your toolchain path and `$RETRO68_INSTALL_PATH` to the path of the cloned repo. Then, run `build.sh` to build for both 68k and PowerPC. 18 | 19 | The resulting file will be the stuffit file `os9fetch.bin` (the old name of the project) in either the `build-68k` or `build-PowerPC` folder. 20 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | function make_for() { 2 | echo "==================" 3 | echo "Making $1" 4 | echo "==================" 5 | mkdir -p build-$1 6 | cd build-$1 7 | cmd="cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_QJS_LIBC=OFF -DPLATFORM=$2 -DRETRO68_ROOT=$RETRO68_TOOLCHAIN_PATH -DCMAKE_TOOLCHAIN_FILE=$RETRO68_INSTALL_PATH/cmake/$2.toolchain.cmake.in" 8 | cmd2="make -j$(nproc)" 9 | $cmd && $cmd2 10 | status=$? 11 | cd .. 12 | return $status 13 | } 14 | 15 | make_for "68k" "retro68" && make_for "PowerPC" "retroppc" -------------------------------------------------------------------------------- /lib/OpenGLLibraryStub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerMacTools/PowerFetch/82ef53f5a1dcd80f8d14f6573c6ca4a2e0da7d08/lib/OpenGLLibraryStub -------------------------------------------------------------------------------- /lib/OpenGLMemoryStub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerMacTools/PowerFetch/82ef53f5a1dcd80f8d14f6573c6ca4a2e0da7d08/lib/OpenGLMemoryStub -------------------------------------------------------------------------------- /lib/OpenGLUtilityStub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerMacTools/PowerFetch/82ef53f5a1dcd80f8d14f6573c6ca4a2e0da7d08/lib/OpenGLUtilityStub -------------------------------------------------------------------------------- /src/console/Console.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2012-2020 Wolfgang Thaller, Davide Bucci 3 | 4 | This file is part of Retro68. 5 | 6 | Retro68 is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Retro68 is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Under Section 7 of GPL version 3, you are granted additional 17 | permissions described in the GCC Runtime Library Exception, version 18 | 3.1, as published by the Free Software Foundation. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with Retro68. If not, see . 22 | */ 23 | 24 | #include "Console.hpp" 25 | #include "MacUtils.h" 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | using namespace retro; 32 | 33 | const char BEL = 7; 34 | const char MAX_LEN = 250; 35 | 36 | Console *Console::currentInstance = NULL; 37 | 38 | Attributes::Attributes(void) 39 | { 40 | reset(); 41 | } 42 | void Attributes::reset(void) 43 | { 44 | cBold = false; 45 | cUnderline = false; 46 | cItalic = false; 47 | } 48 | 49 | bool Attributes::isBold(void) const 50 | { 51 | return cBold; 52 | } 53 | 54 | bool Attributes::isUnderline(void) const 55 | { 56 | return cUnderline; 57 | } 58 | 59 | bool Attributes::isItalic(void) const 60 | { 61 | return cItalic; 62 | } 63 | 64 | void Attributes::setBold(const bool v) 65 | { 66 | cBold = v; 67 | } 68 | 69 | void Attributes::setItalic(const bool v) 70 | { 71 | cItalic = v; 72 | } 73 | 74 | void Attributes::setUnderline(const bool v) 75 | { 76 | cUnderline = v; 77 | } 78 | 79 | inline bool operator==(const Attributes &lhs, const Attributes &rhs) 80 | { 81 | return lhs.isBold() == rhs.isBold() && lhs.isUnderline() == rhs.isUnderline() && lhs.isItalic() == rhs.isItalic(); 82 | } 83 | 84 | inline bool operator!=(const Attributes &lhs, const Attributes &rhs) 85 | { 86 | return !(lhs == rhs); 87 | } 88 | 89 | inline bool operator==(const AttributedChar &lhs, const AttributedChar &rhs) 90 | { 91 | return lhs.c == rhs.c && lhs.attrs == rhs.attrs; 92 | } 93 | 94 | inline bool operator!=(const AttributedChar &lhs, const AttributedChar &rhs) 95 | { 96 | return !(lhs == rhs); 97 | } 98 | 99 | namespace 100 | { 101 | class FontSetup 102 | { 103 | short saveFont, saveSize, saveFace; 104 | 105 | public: 106 | FontSetup() 107 | { 108 | #if TARGET_API_MAC_CARBON 109 | GrafPtr port; 110 | GetPort(&port); 111 | saveFont = GetPortTextFont(port); 112 | saveSize = GetPortTextSize(port); 113 | #else 114 | saveFont = qd.thePort->txFont; 115 | saveSize = qd.thePort->txSize; 116 | saveFace = qd.thePort->txFace; 117 | #endif 118 | TextFont(kFontIDMonaco); 119 | TextSize(9); 120 | TextFace(normal); 121 | } 122 | 123 | ~FontSetup() 124 | { 125 | TextFont(saveFont); 126 | TextSize(saveSize); 127 | TextFace(saveFace); 128 | } 129 | }; 130 | } 131 | 132 | Console::Console() 133 | { 134 | } 135 | 136 | Console::Console(GrafPtr port, Rect r) 137 | { 138 | Init(port, r); 139 | } 140 | 141 | Console::~Console() 142 | { 143 | if (currentInstance == this) 144 | currentInstance = NULL; 145 | } 146 | 147 | void Console::Init(GrafPtr port, Rect r) 148 | { 149 | consolePort = port; 150 | bounds = r; 151 | 152 | PortSetter setport(consolePort); 153 | FontSetup fontSetup; 154 | 155 | cellSizeY = 12; 156 | cellSizeX = CharWidth('M'); 157 | 158 | rows = (bounds.bottom - bounds.top) / cellSizeY; 159 | cols = (bounds.right - bounds.left) / cellSizeX; 160 | 161 | chars = std::vector(rows * cols, AttributedChar(' ', currentAttr)); 162 | 163 | onscreen = chars; 164 | 165 | cursorX = cursorY = 0; 166 | sequenceState = State::noSequence; 167 | } 168 | 169 | void Console::SetAttributes(Attributes aa) 170 | { 171 | TextFace(aa.isBold() ? bold + condense : 0 + aa.isUnderline() ? underline 172 | : 0 + aa.isItalic() ? italic 173 | : 0); 174 | } 175 | 176 | Rect Console::CellRect(short x, short y) 177 | { 178 | return {(short)(bounds.top + y * cellSizeY), (short)(bounds.left + x * cellSizeX), 179 | (short)(bounds.top + (y + 1) * cellSizeY), (short)(bounds.left + (x + 1) * cellSizeX)}; 180 | } 181 | void Console::DrawCell(short x, short y, bool erase) 182 | { 183 | Rect r = CellRect(x, y); 184 | 185 | if (cursorDrawn) 186 | { 187 | if (y == cursorY && x == cursorX) 188 | { 189 | erase = true; 190 | cursorDrawn = false; 191 | } 192 | } 193 | 194 | if (erase) 195 | EraseRect(&r); 196 | MoveTo(r.left, r.bottom - 2); 197 | DrawChar(chars[y * cols + x].c); 198 | } 199 | 200 | void Console::DrawCells(short x1, short x2, short y, bool erase) 201 | { 202 | Rect r = {(short)(bounds.top + y * cellSizeY), (short)(bounds.left + x1 * cellSizeX), 203 | (short)(bounds.top + (y + 1) * cellSizeY), (short)(bounds.left + x2 * cellSizeX)}; 204 | if (cursorDrawn) 205 | { 206 | if (y == cursorY && x1 <= cursorX && x2 > cursorX) 207 | { 208 | erase = true; 209 | cursorDrawn = false; 210 | } 211 | } 212 | 213 | if (erase) 214 | EraseRect(&r); 215 | MoveTo(r.left, r.bottom - 2); 216 | 217 | Attributes a = chars[y * cols + x1].attrs; 218 | SetAttributes(a); 219 | for (int i = x1; i < x2; ++i) 220 | { 221 | if (a != chars[y * cols + i].attrs) 222 | { 223 | a = chars[y * cols + i].attrs; 224 | SetAttributes(a); 225 | } 226 | DrawChar(chars[y * cols + i].c); 227 | } 228 | } 229 | 230 | void Console::Draw(Rect r) 231 | { 232 | if (!consolePort) 233 | return; 234 | PortSetter setport(consolePort); 235 | FontSetup fontSetup; 236 | 237 | SectRect(&r, &bounds, &r); 238 | 239 | short minRow = std::max(0, (r.top - bounds.top) / cellSizeY); 240 | short maxRow = std::min((int)rows, (r.bottom - bounds.top + cellSizeY - 1) / cellSizeY); 241 | 242 | short minCol = std::max(0, (r.left - bounds.left) / cellSizeX); 243 | short maxCol = std::min((int)cols, (r.right - bounds.left + cellSizeX - 1) / cellSizeX); 244 | 245 | EraseRect(&r); 246 | for (short row = minRow; row < maxRow; ++row) 247 | { 248 | DrawCells(minCol, maxCol, row, false); 249 | } 250 | if (cursorDrawn) 251 | { 252 | Rect cursor = CellRect(cursorX, cursorY); 253 | InvertRect(&cursor); 254 | } 255 | onscreen = chars; 256 | } 257 | 258 | void Console::ScrollUp(short n) 259 | { 260 | cursorY--; 261 | std::copy(chars.begin() + cols, chars.end(), chars.begin()); 262 | std::fill(chars.end() - cols, chars.end(), AttributedChar(' ', currentAttr)); 263 | std::copy(onscreen.begin() + cols, onscreen.end(), onscreen.begin()); 264 | std::fill(onscreen.end() - cols, onscreen.end(), AttributedChar(' ', currentAttr)); 265 | RgnHandle rgn = NewRgn(); 266 | ScrollRect(&bounds, 0, -cellSizeY, rgn); 267 | DisposeRgn(rgn); 268 | dirtyRect.top = dirtyRect.top > 0 ? dirtyRect.top - 1 : 0; 269 | dirtyRect.bottom = dirtyRect.bottom > 0 ? dirtyRect.bottom - 1 : 0; 270 | } 271 | 272 | bool Console::ProcessEscSequence(char c) 273 | { 274 | switch (sequenceState) 275 | { 276 | case State::noSequence: 277 | return false; // Break is not needed there. 278 | case State::waitingForSequenceStart: 279 | if (c == '[') 280 | sequenceState = State::waitingForControlSequence; 281 | else if (c == ']') 282 | sequenceState = State::waitingForOSCStart; 283 | else 284 | sequenceState = State::noSequence; // Unrecognized sequence 285 | break; 286 | case State::waitingForControlSequence: 287 | sequenceState = State::waitingForM; 288 | switch (c) 289 | { 290 | case '0': // Normal character 291 | currentAttr.reset(); 292 | break; 293 | case '1': // Bold 294 | currentAttr.setBold(true); 295 | break; 296 | case '3': // Italic 297 | currentAttr.setItalic(true); 298 | break; 299 | case '4': // Underline 300 | currentAttr.setUnderline(true); 301 | break; 302 | default: 303 | sequenceState = State::noSequence; // Unrecognized sequence 304 | } 305 | break; 306 | case State::waitingForM: 307 | if (c == 'm') 308 | sequenceState = State::noSequence; // Normal end of sequence 309 | else 310 | sequenceState = State::noSequence; // Unrecognized sequence (but we end it anyway!) 311 | break; 312 | case State::waitingForOSCStart: 313 | if (c == '0') 314 | sequenceState = State::waitingForSemicolon; 315 | else 316 | sequenceState = State::noSequence; // Normal end of sequence 317 | break; 318 | case State::waitingForSemicolon: 319 | if (c == ';') 320 | { 321 | sequenceState = State::inWindowName; 322 | windowName = ""; 323 | } 324 | else 325 | sequenceState = State::noSequence; // Normal end of sequence 326 | break; 327 | case State::inWindowName: 328 | if (c == BEL) 329 | { 330 | setWindowName(std::move(windowName)); 331 | sequenceState = State::noSequence; // Normal end of sequence 332 | } 333 | else 334 | { 335 | if (windowName.size() < MAX_LEN) // Ignore subsequent characters 336 | windowName += c; 337 | } 338 | break; 339 | default: 340 | sequenceState = State::noSequence; 341 | break; 342 | } 343 | return true; 344 | } 345 | 346 | long colors[]{ 347 | greenColor, 348 | greenColor, 349 | greenColor, 350 | greenColor, 351 | greenColor, 352 | greenColor, 353 | yellowColor, 354 | yellowColor, 355 | redColor, 356 | redColor, 357 | redColor, 358 | redColor, 359 | magentaColor, 360 | magentaColor, 361 | blueColor, 362 | blueColor, 363 | greenColor, 364 | }; 365 | 366 | int curColor = 0; 367 | 368 | void Console::PutCharNoUpdate(char c) 369 | { 370 | if (ProcessEscSequence(c)) 371 | return; 372 | 373 | InvalidateCursor(); 374 | switch (c) 375 | { 376 | case '\033': // Begin of an ANSI escape sequence 377 | sequenceState = State::waitingForSequenceStart; 378 | break; 379 | case '\r': 380 | cursorX = 0; 381 | break; 382 | case '\n': 383 | cursorY++; 384 | cursorX = 0; 385 | if (cursorY >= rows) 386 | ScrollUp(); 387 | 388 | break; 389 | default: 390 | chars[cursorY * cols + cursorX].c = c; 391 | chars[cursorY * cols + cursorX].attrs = currentAttr; 392 | 393 | if (dirtyRect.right == 0) 394 | { 395 | dirtyRect.right = (dirtyRect.left = cursorX) + 1; 396 | dirtyRect.bottom = (dirtyRect.top = cursorY) + 1; 397 | } 398 | else 399 | { 400 | dirtyRect.left = std::min(dirtyRect.left, cursorX); 401 | dirtyRect.top = std::min(dirtyRect.top, cursorY); 402 | dirtyRect.right = std::max(dirtyRect.right, short(cursorX + 1)); 403 | dirtyRect.bottom = std::max(dirtyRect.bottom, short(cursorY + 1)); 404 | } 405 | 406 | cursorX++; 407 | if (cursorX >= cols) 408 | PutCharNoUpdate('\n'); 409 | } 410 | } 411 | 412 | void Console::Update() 413 | { 414 | PortSetter setport(consolePort); 415 | FontSetup fontSetup; 416 | 417 | BackColor(blackColor); 418 | ForeColor(whiteColor); 419 | 420 | for (short row = dirtyRect.top; row < dirtyRect.bottom; ++row) 421 | { 422 | short start = -1; 423 | bool needclear = false; 424 | for (short col = dirtyRect.left; col < dirtyRect.right; ++col) 425 | { 426 | AttributedChar old = onscreen[row * cols + col]; 427 | if (chars[row * cols + col] != old) 428 | { 429 | if (start == -1) 430 | start = col; 431 | if (old.c != ' ') 432 | needclear = true; 433 | onscreen[row * cols + col] = chars[row * cols + col]; 434 | } 435 | else 436 | { 437 | 438 | if (start != -1) 439 | DrawCells(start, col, row, needclear); 440 | start = -1; 441 | needclear = false; 442 | } 443 | } 444 | if (start != -1) 445 | DrawCells(start, dirtyRect.right, row, needclear); 446 | } 447 | dirtyRect = Rect(); 448 | 449 | if (cursorVisible != cursorDrawn) 450 | { 451 | Rect r = CellRect(cursorX, cursorY); 452 | if (cursorDrawn) 453 | DrawCell(cursorX, cursorY, true); 454 | else 455 | InvertRect(&r); 456 | cursorDrawn = !cursorDrawn; 457 | } 458 | 459 | #if TARGET_API_MAC_CARBON 460 | QDFlushPortBuffer(consolePort, NULL); 461 | #endif 462 | } 463 | 464 | void Console::putch(char c) 465 | { 466 | if (!rows) 467 | return; 468 | PutCharNoUpdate(c); 469 | Update(); 470 | } 471 | 472 | void Console::write(const char *p, int n) 473 | { 474 | if (!rows) 475 | return; 476 | 477 | for (int i = 0; i < n; i++) 478 | Console::currentInstance->PutCharNoUpdate(*p++); 479 | Update(); 480 | } 481 | 482 | std::string Console::ReadLine() 483 | { 484 | if (!consolePort) 485 | return ""; 486 | 487 | std::string buffer; 488 | char c; 489 | 490 | do 491 | { 492 | c = WaitNextChar(); 493 | if (!c) 494 | { 495 | eof = true; 496 | return ""; 497 | } 498 | 499 | if (c == '\r') 500 | c = '\n'; 501 | 502 | if (c == '\b') 503 | { 504 | if (buffer.size()) 505 | { 506 | InvalidateCursor(); 507 | cursorX--; 508 | PutCharNoUpdate(' '); 509 | cursorX--; 510 | Update(); 511 | 512 | buffer.resize(buffer.size() - 1); 513 | } 514 | 515 | continue; 516 | } 517 | 518 | putch(c); 519 | buffer.append(1, c); 520 | } while (c != '\n'); 521 | return buffer; 522 | } 523 | 524 | void Console::InvalidateCursor() 525 | { 526 | if (cursorDrawn) 527 | { 528 | PortSetter setport(consolePort); 529 | DrawCell(cursorX, cursorY, true); 530 | cursorDrawn = false; 531 | } 532 | } 533 | 534 | void Console::Idle() 535 | { 536 | long ticks = TickCount(); 537 | if (ticks - blinkTicks > 60) 538 | { 539 | cursorVisible = !cursorVisible; 540 | blinkTicks = ticks; 541 | Update(); 542 | } 543 | } 544 | 545 | void Console::Reshape(Rect newBounds) 546 | { 547 | if (!consolePort) 548 | return; 549 | 550 | bounds = newBounds; 551 | 552 | short newRows = (bounds.bottom - bounds.top) / cellSizeY; 553 | short newCols = (bounds.right - bounds.left) / cellSizeX; 554 | 555 | short upshift = 0; 556 | if (cursorY >= newRows) 557 | { 558 | upshift = cursorY - (newRows - 1); 559 | 560 | InvalidateCursor(); 561 | cursorY = std::max(newRows - 1, 0); 562 | } 563 | 564 | std::vector newChars(newRows * newCols, AttributedChar(' ', currentAttr)); 565 | for (short row = 0; row < newRows && row + upshift < rows; row++) 566 | { 567 | AttributedChar *src = &chars[(row + upshift) * cols]; 568 | AttributedChar *dst = &newChars[row * newCols]; 569 | std::copy(src, src + std::min(cols, newCols), dst); 570 | } 571 | chars.swap(newChars); 572 | 573 | onscreen = newChars; 574 | 575 | rows = newRows; 576 | cols = newCols; 577 | 578 | dirtyRect = Rect{0, 0, rows, cols}; 579 | EraseRect(&newBounds); 580 | Update(); 581 | Draw(newBounds); 582 | } 583 | 584 | char Console::WaitNextChar() 585 | { 586 | return 0; 587 | } -------------------------------------------------------------------------------- /src/console/Console.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2012-2020 Wolfgang Thaller, Davide Bucci 3 | 4 | This file is part of Retro68. 5 | 6 | Retro68 is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Retro68 is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Under Section 7 of GPL version 3, you are granted additional 17 | permissions described in the GCC Runtime Library Exception, version 18 | 3.1, as published by the Free Software Foundation. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with Retro68. If not, see . 22 | */ 23 | #ifndef RETRO68_CONSOLE_H_ 24 | #define RETRO68_CONSOLE_H_ 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace retro 31 | { 32 | void InitConsole(); 33 | 34 | class Attributes 35 | { 36 | public: 37 | bool isBold(void) const; 38 | bool isUnderline(void) const; 39 | bool isItalic(void) const; 40 | 41 | void setBold(const bool v); 42 | void setUnderline(const bool v); 43 | void setItalic(const bool v); 44 | 45 | Attributes(void); 46 | void reset(void); 47 | 48 | private: 49 | bool cBold; 50 | bool cUnderline; 51 | bool cItalic; 52 | }; 53 | 54 | class AttributedChar 55 | { 56 | public: 57 | char c; 58 | Attributes attrs; 59 | AttributedChar(char cc, Attributes aa) 60 | { 61 | c = cc; 62 | attrs = aa; 63 | } 64 | }; 65 | 66 | enum class State 67 | { 68 | noSequence, 69 | waitingForSequenceStart, 70 | waitingForControlSequence, 71 | waitingForM, 72 | waitingForOSCStart, 73 | waitingForSemicolon, 74 | inWindowName 75 | }; 76 | 77 | class Console 78 | { 79 | public: 80 | Console(); 81 | Console(GrafPtr port, Rect r); 82 | ~Console(); 83 | 84 | void Reshape(Rect newBounds); 85 | 86 | void Draw(Rect r); 87 | void Draw() { Draw(bounds); } 88 | void putch(char c); 89 | 90 | void write(const char *s, int n); 91 | std::string ReadLine(); 92 | 93 | static Console *currentInstance; 94 | 95 | short GetRows() const { return rows; } 96 | short GetCols() const { return cols; } 97 | 98 | virtual void setWindowName(std::string newName) {}; 99 | 100 | void Idle(); 101 | 102 | bool IsEOF() const { return eof; } 103 | void Update(); 104 | void PutCharNoUpdate(char c); 105 | 106 | private: 107 | State sequenceState; 108 | std::string windowName; 109 | GrafPtr consolePort = nullptr; 110 | Rect bounds; 111 | Attributes currentAttr; 112 | 113 | std::vector chars, onscreen; 114 | 115 | short cellSizeX; 116 | short cellSizeY; 117 | 118 | short rows = 0, cols = 0; 119 | 120 | short cursorX, cursorY; 121 | 122 | Rect dirtyRect = {}; 123 | 124 | long blinkTicks = 0; 125 | bool cursorDrawn = false; 126 | bool cursorVisible = true; 127 | bool eof = false; 128 | 129 | short CalcStartX(short x, short y); 130 | Rect CellRect(short x, short y); 131 | void DrawCell(short x, short y, bool erase = true); 132 | void DrawCells(short x1, short x2, short y, bool erase = true); 133 | void ScrollUp(short n = 1); 134 | bool ProcessEscSequence(char c); 135 | void SetAttributes(Attributes aa); 136 | 137 | void InvalidateCursor(); 138 | 139 | virtual char WaitNextChar(); 140 | 141 | protected: 142 | void Init(GrafPtr port, Rect r); 143 | }; 144 | 145 | } 146 | 147 | #endif /* RETRO68_CONSOLE_H_ */ -------------------------------------------------------------------------------- /src/console/ConsoleWindow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2012-2020 Wolfgang Thaller, Davide Bucci 3 | 4 | This file is part of Retro68. 5 | 6 | Retro68 is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Retro68 is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Under Section 7 of GPL version 3, you are granted additional 17 | permissions described in the GCC Runtime Library Exception, version 18 | 3.1, as published by the Free Software Foundation. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with Retro68. If not, see . 22 | */ 23 | 24 | #include "ConsoleWindow.hpp" 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | using namespace retro; 31 | 32 | namespace 33 | { 34 | std::unordered_map *windows = NULL; 35 | } 36 | 37 | ConsoleWindow::ConsoleWindow(Rect r, ConstStr255Param title) 38 | { 39 | GrafPtr port; 40 | win = NewWindow(NULL, &r, "\pos9fetch", true, 0, (WindowPtr)-1, true, 0); 41 | 42 | #if !TARGET_API_MAC_CARBON 43 | port = win; 44 | Rect portRect = port->portRect; 45 | #else 46 | port = GetWindowPort(win); 47 | Rect portRect; 48 | GetPortBounds(port, &portRect); 49 | #endif 50 | #ifdef FOR_PPC 51 | portRect = (Rect){ 52 | .top = 0, 53 | .left = 0, 54 | .bottom = 480, 55 | .right = 640, 56 | }; 57 | #endif 58 | port->portRect = portRect; 59 | 60 | SetPort(port); 61 | EraseRect(&portRect); 62 | 63 | if (!windows) 64 | windows = new std::unordered_map(); 65 | (*windows)[win] = this; 66 | 67 | Init(port, portRect); 68 | } 69 | 70 | ConsoleWindow::~ConsoleWindow() 71 | { 72 | windows->erase(win); 73 | DisposeWindow(win); 74 | } 75 | 76 | void ConsoleWindow::setWindowName(std::string newName) 77 | { 78 | Str255 pname; 79 | #if TARGET_API_MAC_CARBON 80 | // Carbon has the new, sane version. 81 | c2pstrcpy(pname, newName.c_str()); 82 | #else 83 | // It is also availble in various glue code libraries and 84 | // in some versions of InterfaceLib, but it's confusing. 85 | // Using the inplace variant, c2pstr, isn't much better than 86 | // doing things by hand: 87 | strncpy((char *)&pname[1], newName.c_str(), 255); 88 | pname[0] = newName.length(); 89 | #endif 90 | 91 | SetWTitle(win, pname); 92 | } 93 | 94 | char ConsoleWindow::WaitNextChar() 95 | { 96 | EventRecord event; 97 | WindowPtr eventWin; 98 | ConsoleWindow *realConsole; 99 | #if TARGET_API_MAC_CARBON 100 | Rect *boundsPtr = NULL; 101 | #else 102 | Rect *boundsPtr = &qd.screenBits.bounds; 103 | #endif 104 | 105 | do 106 | { 107 | #if TARGET_API_MAC_CARBON 108 | #define SystemTask() 109 | #endif 110 | SystemTask(); 111 | Idle(); 112 | while (!GetNextEvent(everyEvent, &event)) 113 | { 114 | SystemTask(); 115 | Idle(); 116 | } 117 | 118 | switch (event.what) 119 | { 120 | case updateEvt: 121 | eventWin = (WindowPtr)event.message; 122 | realConsole = (*windows)[(WindowPtr)event.message]; 123 | if (realConsole) 124 | { 125 | Rect updateRect; 126 | BeginUpdate(eventWin); 127 | #if TARGET_API_MAC_CARBON 128 | RgnHandle rgn = NewRgn(); 129 | GetPortVisibleRegion(GetWindowPort(eventWin), rgn); 130 | GetRegionBounds(rgn, &updateRect); 131 | DisposeRgn(rgn); 132 | #else 133 | updateRect = (*qd.thePort->visRgn)->rgnBBox; // Life was simple back then. 134 | #endif 135 | realConsole->Draw(updateRect); 136 | EndUpdate(eventWin); 137 | } 138 | break; 139 | case mouseDown: 140 | switch (FindWindow(event.where, &eventWin)) 141 | { 142 | case inDrag: 143 | DragWindow(eventWin, event.where, boundsPtr); 144 | break; 145 | case inGrow: 146 | { 147 | long growResult = GrowWindow(eventWin, event.where, boundsPtr); 148 | SizeWindow(eventWin, growResult & 0xFFFF, growResult >> 16, false); 149 | Reshape(Rect{0, 0, (short)(growResult >> 16), (short)(growResult & 0xFFFF)}); 150 | } 151 | break; 152 | case inGoAway: 153 | { 154 | if (TrackGoAway(eventWin, event.where)) 155 | exit(0); 156 | } 157 | break; 158 | } 159 | break; 160 | } 161 | } while (event.what != keyDown && event.what != autoKey); 162 | 163 | return event.message & charCodeMask; 164 | } -------------------------------------------------------------------------------- /src/console/ConsoleWindow.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2012-2020 Wolfgang Thaller, Davide Bucci 3 | 4 | This file is part of Retro68. 5 | 6 | Retro68 is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Retro68 is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Under Section 7 of GPL version 3, you are granted additional 17 | permissions described in the GCC Runtime Library Exception, version 18 | 3.1, as published by the Free Software Foundation. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with Retro68. If not, see . 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "Console.hpp" 29 | 30 | namespace retro 31 | { 32 | class ConsoleWindow : public Console 33 | { 34 | public: 35 | ConsoleWindow(Rect r, ConstStr255Param title); 36 | ~ConsoleWindow(); 37 | void setWindowName(std::string newName); 38 | 39 | private: 40 | WindowPtr win; 41 | 42 | virtual char WaitNextChar(); 43 | }; 44 | } -------------------------------------------------------------------------------- /src/console/InitConsole.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Wolfgang Thaller. 3 | 4 | This file is part of Retro68. 5 | 6 | Retro68 is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Retro68 is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Under Section 7 of GPL version 3, you are granted additional 17 | permissions described in the GCC Runtime Library Exception, version 18 | 3.1, as published by the Free Software Foundation. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with Retro68. If not, see . 22 | */ 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | #include "MacUtils.h" 36 | #include "Console.hpp" 37 | #include "ConsoleWindow.hpp" 38 | 39 | namespace retro 40 | { 41 | void InitConsole(); 42 | } 43 | 44 | using namespace retro; 45 | 46 | void retro::InitConsole() 47 | { 48 | if (Console::currentInstance) 49 | return; 50 | Console::currentInstance = (Console *)-1; 51 | 52 | #if !TARGET_API_MAC_CARBON 53 | InitGraf(&qd.thePort); 54 | InitFonts(); 55 | InitWindows(); 56 | InitMenus(); 57 | 58 | Rect r = qd.screenBits.bounds; 59 | #else 60 | Rect r = (*GetMainDevice())->gdRect; 61 | #endif 62 | 63 | #ifdef FOR_PPC 64 | r = (Rect){ 65 | .top = (r.bottom / 4), 66 | .left = (r.right / 4), 67 | .bottom = (r.bottom / 4) + 480, 68 | .right = (r.bottom / 4) + 640, 69 | }; 70 | #endif 71 | { 72 | // give MultiFinder a chance to bring the App to front 73 | // see Technote TB 35 - MultiFinder Miscellanea 74 | // "If your application [...] has the canBackground bit set in the 75 | // size resource, then it should call _EventAvail several times 76 | // (or _WaitNextEvent or _GetNextEvent) before putting up the splash 77 | // screen, or the splash screen will come up behind the frontmost 78 | // layer. If the canBackground bit is set, MultiFinder will not move 79 | // your layer to the front until you call _GetNextEvent, 80 | // _WaitNextEvent, or _EventAvail." 81 | 82 | EventRecord event; 83 | for (int i = 0; i < 5; i++) 84 | EventAvail(everyEvent, &event); 85 | } 86 | 87 | r.top += 40; 88 | Console::currentInstance = new ConsoleWindow(r, "\pos9fetch"); 89 | InitCursor(); 90 | } 91 | 92 | extern "C" ssize_t _consolewrite(int fd, const void *buf, size_t count) 93 | { 94 | if (!Console::currentInstance) 95 | InitConsole(); 96 | if (Console::currentInstance == (Console *)-1) 97 | return 0; 98 | 99 | Console::currentInstance->write((const char *)buf, count); 100 | return count; 101 | } 102 | 103 | extern "C" ssize_t _consoleread(int fd, void *buf, size_t count) 104 | { 105 | if (!Console::currentInstance) 106 | InitConsole(); 107 | if (Console::currentInstance == (Console *)-1) 108 | return 0; 109 | 110 | static std::string consoleBuf; 111 | if (consoleBuf.size() == 0) 112 | consoleBuf = Console::currentInstance->ReadLine(); 113 | 114 | if (count > consoleBuf.size()) 115 | count = consoleBuf.size(); 116 | memcpy(buf, consoleBuf.data(), count); 117 | consoleBuf = consoleBuf.substr(count); 118 | return count; 119 | } -------------------------------------------------------------------------------- /src/console/MacUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2012 Wolfgang Thaller. 3 | 4 | This file is part of Retro68. 5 | 6 | Retro68 is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Retro68 is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | Under Section 7 of GPL version 3, you are granted additional 17 | permissions described in the GCC Runtime Library Exception, version 18 | 3.1, as published by the Free Software Foundation. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with Retro68. If not, see . 22 | */ 23 | 24 | #include 25 | #include 26 | 27 | namespace retro 28 | { 29 | class PortSetter 30 | { 31 | GrafPtr save; 32 | 33 | public: 34 | PortSetter(GrafPtr port) 35 | { 36 | ::GetPort(&save); 37 | ::SetPort(port); 38 | } 39 | 40 | ~PortSetter() 41 | { 42 | ::SetPort(save); 43 | } 44 | }; 45 | } -------------------------------------------------------------------------------- /src/detection/68kextras.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace detection 5 | { 6 | 7 | void 8 | fpu() 9 | { 10 | SysEnvRec rec; 11 | SysEnvirons(1, &rec); 12 | if (rec.hasFPU) 13 | { 14 | printf("FPU: Yes"); 15 | } 16 | else 17 | { 18 | printf("FPU: No"); 19 | } 20 | } 21 | 22 | void color() 23 | { 24 | SysEnvRec rec; 25 | SysEnvirons(1, &rec); 26 | if (rec.hasColorQD) 27 | { 28 | printf("Color: Yes"); 29 | } 30 | else 31 | { 32 | printf("Color: No"); 33 | } 34 | } 35 | 36 | void keyboard() 37 | { 38 | SysEnvRec rec; 39 | SysEnvirons(1, &rec); 40 | switch (rec.keyBoardType) 41 | { 42 | case 0: 43 | printf("Keyboard: Unknown"); 44 | break; 45 | case 1: 46 | printf("Keyboard: Macintosh Keyboard"); 47 | break; 48 | case 2: 49 | printf("Keyboard: Macintosh Keyboard (w/ Keypad)"); 50 | break; 51 | case 3: 52 | printf("Keyboard: Macintosh Plus Keyboard (w/ Keypad)"); 53 | break; 54 | case 4: 55 | printf("Keyboard: Apple Extended Keyboard"); 56 | break; 57 | case 5: 58 | printf("Keyboard: Standard ADB Keyboard"); 59 | break; 60 | case 6: 61 | printf("Keyboard: Portable ADB Keyboard"); 62 | break; 63 | case 7: 64 | printf("Keyboard: Portable ISO Keyboard"); 65 | break; 66 | case 8: 67 | printf("Keyboard: Standard ISO ADB"); 68 | break; 69 | case 9: 70 | printf("Keyboard: Extended ISO ADB"); 71 | break; 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /src/detection/battery.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace detection 5 | { 6 | int battery_count() 7 | { 8 | return BatteryCount(); 9 | } 10 | 11 | bool has_battery() 12 | { 13 | return detection::battery_count() >= 1; 14 | } 15 | void battery() 16 | { 17 | 18 | short count = (short)detection::battery_count(); 19 | 20 | for (short i = 0; i < count - 1; i++) 21 | { 22 | BatteryInfo info; 23 | GetScaledBatteryInfo(i, &info); 24 | BatteryTimeRec time; 25 | GetBatteryTimes(i, &time); 26 | printf("Battery"); 27 | if (count - 1 >= 2) 28 | { 29 | printf(" %d", i); 30 | } 31 | printf(": %f%%", ((float)info.batteryLevel / 255.0f) * 100.0); 32 | if (count - 1 >= 2) 33 | { 34 | printf(", ", i); 35 | } 36 | if (info.flags & batteryCharging == batteryCharging) 37 | { 38 | printf(" (Charging)"); 39 | } 40 | if (info.flags & batteryDeadBit == batteryDeadBit) 41 | { 42 | printf(" (Dead)"); 43 | } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/detection/cpu.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "functions.hpp" 6 | 7 | #include "xpostcode/CPUDevice.h" 8 | #include 9 | #include 10 | 11 | #include "xpostcode/CPUDevice.h" 12 | 13 | namespace detection 14 | { 15 | 16 | #ifdef FOR_68K 17 | void cpu_68k(); 18 | void cpu() 19 | { 20 | cpu_68k(); 21 | } 22 | #endif 23 | #ifdef FOR_PPC 24 | void cpu_ppc(); 25 | void cpu() 26 | { 27 | cpu_ppc(); 28 | } 29 | #endif 30 | void clockSpeed(); 31 | 32 | void cpu_68k() 33 | { 34 | int ver = os_version(); 35 | 36 | long procType; 37 | if (ver >= 0x605) 38 | { 39 | procType = detection::gestalt(gestaltProcessorType); 40 | } 41 | else 42 | { 43 | SysEnvRec rec; 44 | SysEnvirons(1, &rec); 45 | procType = rec.processor; 46 | } 47 | if (procType != NULL) 48 | { 49 | switch (procType) 50 | { 51 | case gestalt68000: 52 | printf("CPU: 68000"); 53 | break; 54 | case gestalt68010: 55 | printf("CPU: 68010"); 56 | break; 57 | case gestalt68020: 58 | printf("CPU: 68020"); 59 | break; 60 | case gestalt68030: 61 | printf("CPU: 68030"); 62 | break; 63 | case gestalt68040: 64 | printf("CPU: 68040"); 65 | break; 66 | } 67 | 68 | #ifdef FOR_PPC 69 | int ver = os_version(); 70 | if (ver >= 0x605) 71 | { 72 | clockSpeed(); 73 | } 74 | #endif 75 | printf(" (ID: %d)", procType); 76 | } 77 | } 78 | 79 | void cpu_ppc() 80 | { 81 | CPUDevice::Initialize(); 82 | auto vec = CPUDevice::GetCPUS(); 83 | for (int i = 0; i < vec.size(); i++) 84 | { 85 | UInt32 propSize; 86 | auto entry = vec.at(i); 87 | 88 | int cpuNumber = 0; 89 | auto err = RegistryPropertyGetSize(&entry, kCPUIDPropName, &propSize); 90 | if ((err == noErr) && (propSize == sizeof(cpuNumber))) 91 | { 92 | ThrowIfOSErr_AC(RegistryPropertyGet(&entry, kCPUIDPropName, &cpuNumber, &propSize)); 93 | } 94 | 95 | uint processorVersion = 0; 96 | err = RegistryPropertyGetSize(&entry, kCPUVersionPropName, &propSize); 97 | if ((err == noErr) && (propSize == sizeof(processorVersion))) 98 | { 99 | ThrowIfOSErr_AC(RegistryPropertyGet(&entry, kCPUVersionPropName, &processorVersion, &propSize)); 100 | } 101 | std::string name; 102 | 103 | switch (processorVersion) 104 | { 105 | case 0x00010001: 106 | name = "PowerPC 601 Rev. 0.1"; 107 | break; 108 | case 0x00010002: 109 | name = "PowerPC 601 Rev. 0.1"; 110 | break; 111 | case 0x00030001: 112 | name = "PowerPC 603 Rev. 0.1"; 113 | break; 114 | case 0x00060101: 115 | name = "PowerPC 603e Rev. 1.1"; 116 | break; 117 | case 0x00060102: 118 | name = "PowerPC 603e Rev. 1.2"; 119 | break; 120 | case 0x00060103: 121 | name = "PowerPC 603e Rev. 1.3"; 122 | break; 123 | case 0x00060104: 124 | name = "PowerPC 603e Rev. 1.4"; 125 | break; 126 | case 0x00060202: 127 | name = "PowerPC 603e Rev. 2.2"; 128 | break; 129 | case 0x00060300: 130 | name = "PowerPC 603e Rev. 3.0"; 131 | break; 132 | case 0x00060400: 133 | name = "PowerPC 603e Rev. 4.0"; 134 | break; 135 | case 0x00060401: 136 | name = "PowerPC 603e Rev. 4.1"; 137 | break; 138 | case 0x00070101: 139 | name = "PowerPC 603ev Rev. 1.1"; 140 | break; 141 | case 0x00071201: 142 | name = "PowerPC 603r Rev. 2.1"; 143 | break; 144 | case 0x00040103: 145 | name = "PowerPC 604 Rev. 1.3"; 146 | break; 147 | case 0x00090204: 148 | name = "PowerPC 604e Rev. 2.4"; 149 | break; 150 | case 0x00080100: 151 | name = "PowerPC G3 740/750 Rev. 1.0"; 152 | break; 153 | case 0x00080200: 154 | name = "PowerPC G3 740/750 Rev. 2.0"; 155 | break; 156 | case 0x00080300: 157 | name = "PowerPC G3 740/750 Rev. 3.0"; 158 | break; 159 | case 0x00080301: 160 | name = "PowerPC G3 740/750 Rev. 3.1"; 161 | break; 162 | case 0x00082202: 163 | name = "PowerPC G3 750CX Rev. 2.2"; 164 | break; 165 | case 0x00082214: 166 | name = "PowerPC G3 750CXe Rev. 2.4"; 167 | break; 168 | case 0x00082311: 169 | name = "PowerPC G3 750CXe Rev. 3.1"; 170 | break; 171 | case 0x70000100: 172 | case 0x70000101: 173 | case 0x70000102: 174 | case 0x70000103: 175 | case 0x70000104: 176 | case 0x70000105: 177 | case 0x70000106: 178 | case 0x70000107: 179 | case 0x70000108: 180 | case 0x70000109: 181 | case 0x7000010A: 182 | case 0x7000010B: 183 | case 0x7000010C: 184 | case 0x7000010D: 185 | case 0x7000010E: 186 | case 0x7000010F: 187 | name = "PowerPC G3 750FX Rev. 1.x"; 188 | break; 189 | case 0x70000200: 190 | name = "PowerPC G3 750FX Rev. 2.0"; 191 | break; 192 | case 0x70000201: 193 | name = "PowerPC G3 750FX Rev. 2.1"; 194 | break; 195 | case 0x70000202: 196 | name = "PowerPC G3 750FX Rev. 2.2"; 197 | break; 198 | case 0x70000203: 199 | name = "PowerPC G3 750FX Rev. 2.3"; 200 | break; 201 | case 0x00080202: 202 | name = "PowerPC G3 740(P)/750(P) Rev. 1.1/1.2/2.1"; 203 | break; 204 | case 0x00083100: 205 | name = "PowerPC G3 745/755 Rev. 1.0"; 206 | break; 207 | case 0x00083101: 208 | name = "PowerPC G3 745/755 Rev. 1.1"; 209 | break; 210 | case 0x00083200: 211 | name = "PowerPC G3 745/755 Rev. 2.0"; 212 | break; 213 | case 0x00083201: 214 | name = "PowerPC G3 745/755 Rev. 2.1"; 215 | break; 216 | case 0x00083202: 217 | name = "PowerPC G3 745/755 Rev. 2.2"; 218 | break; 219 | case 0x00083203: 220 | name = "PowerPC G3 745/755 Rev. 2.3"; 221 | break; 222 | case 0x00083204: 223 | name = "PowerPC G3 745/755 Rev. 2.4"; 224 | break; 225 | case 0x00083205: 226 | name = "PowerPC G3 745/755 Rev. 2.5"; 227 | break; 228 | case 0x00083206: 229 | name = "PowerPC G3 745/755 Rev. 2.6"; 230 | break; 231 | case 0x00083207: 232 | name = "PowerPC G3 745/755 Rev. 2.7"; 233 | break; 234 | case 0x00083208: 235 | name = "PowerPC G3 745/755 Rev. 2.8"; 236 | break; 237 | case 0x000c0101: 238 | name = "PowerPC G4 7400 Rev. 1.1"; 239 | break; 240 | case 0x000c0200: 241 | name = "PowerPC G4 7400 Rev. 2.0"; 242 | break; 243 | case 0x000c0202: 244 | name = "PowerPC G4 7400 Rev. 2.2"; 245 | break; 246 | case 0x000c0206: 247 | name = "PowerPC G4 7400 Rev. 2.6"; 248 | break; 249 | case 0x000c0207: 250 | name = "PowerPC G4 7400 Rev. 2.7"; 251 | break; 252 | case 0x000c0209: 253 | name = "PowerPC G4 7400 Rev. 2.8"; 254 | break; 255 | case 0x000c0208: 256 | name = "PowerPC G4 7400 Rev. 2.9"; 257 | break; 258 | case 0x800c1101: 259 | name = "PowerPC G4 7410 Rev. 1.1"; 260 | break; 261 | case 0x800c1102: 262 | name = "PowerPC G4 7410 Rev. 1.2"; 263 | break; 264 | case 0x800c1103: 265 | name = "PowerPC G4 7410 Rev. 1.3"; 266 | break; 267 | case 0x800c1104: 268 | name = "PowerPC G4 7410 Rev. 1.4"; 269 | break; 270 | case 0x80000100: 271 | name = "PowerPC G4 7450 Rev. 1.0"; 272 | break; 273 | case 0x80000101: 274 | name = "PowerPC G4 7450 Rev. 1.1"; 275 | break; 276 | case 0x80000102: 277 | name = "PowerPC G4 7450 Rev. 1.2"; 278 | break; 279 | case 0x80000200: 280 | name = "PowerPC G4 7450 Rev. 2.0"; 281 | break; 282 | case 0x80000201: 283 | name = "PowerPC G4 7441/7450 Rev. 2.1"; 284 | break; 285 | case 0x80000203: 286 | name = "PowerPC G4 7441/7451 Rev. 2.3"; 287 | break; 288 | case 0x80000202: 289 | name = "PowerPC G4 7441 Rev. 2.2"; 290 | break; 291 | case 0x80010201: 292 | name = "PowerPC G4 7445/7455 Rev. 2.1"; 293 | break; 294 | case 0x80010302: 295 | name = "PowerPC G4 7445/7455 Rev. 3.2"; 296 | break; 297 | case 0x80010303: 298 | name = "PowerPC G4 7445/7455 Rev. 3.3"; 299 | break; 300 | case 0x80010304: 301 | name = "PowerPC G4 7445/7455 Rev. 3.4"; 302 | break; 303 | case 0x80020100: 304 | name = "PowerPC G4 7447/7457 Rev. 1.0"; 305 | break; 306 | case 0x80020101: 307 | name = "PowerPC G4 7447/7457 Rev. 1.1"; 308 | break; 309 | case 0x80020102: 310 | name = "PowerPC G4 7447/7457 Rev. 1.2"; 311 | break; 312 | case 0x00390202: 313 | name = "PowerPC G5 970 Rev. 2.2"; 314 | break; 315 | case 0x003c0300: 316 | name = "PowerPC G5 970FX Rev. 3.0"; 317 | break; 318 | case 0x00200000: 319 | name = "PowerPC 403GA"; 320 | break; 321 | case 0x00200100: 322 | name = "PowerPC 403GB"; 323 | break; 324 | case 0x00200200: 325 | name = "PowerPC 403GC"; 326 | break; 327 | case 0x00201400: 328 | name = "PowerPC 403GCX"; 329 | break; 330 | case 0x40110000: 331 | name = "PowerPC 405GP"; 332 | break; 333 | case 0x40110040: 334 | name = "PowerPC 405GP Rev. B"; 335 | break; 336 | case 0x40110082: 337 | name = "PowerPC 405GP Rev. C"; 338 | break; 339 | case 0x401100C4: 340 | name = "PowerPC 405GP Rev. D"; 341 | break; 342 | case 0x40110145: 343 | name = "PowerPC 405GP Rev. E or 405CR Rev. C"; 344 | break; 345 | case 0x40110041: 346 | name = "PowerPC 405CR Rev. A"; 347 | break; 348 | case 0x401100C5: 349 | name = "PowerPC 405CR Rev. B"; 350 | break; 351 | case 0x51210950: 352 | name = "PowerPC 405EP Rev. A or Rev. B"; 353 | break; 354 | case 0x50910951: 355 | name = "PowerPC 405GPR Rev. B"; 356 | break; 357 | case 0x41511460: 358 | name = "PowerPC 405EZ Rev. A"; 359 | break; 360 | case 0x12911471: 361 | name = "PowerPC 405EXR2 Rev. A"; 362 | break; 363 | case 0x12911477: 364 | name = "PowerPC 405EX1 Rev. A"; 365 | break; 366 | case 0x1291147B: 367 | name = "PowerPC 405EXR1 Rev. C"; 368 | break; 369 | case 0x12911479: 370 | name = "PowerPC 405EXR2 Rev. C"; 371 | break; 372 | case 0x1291147F: 373 | name = "PowerPC 405EX1 Rev. C"; 374 | break; 375 | case 0x1291147D: 376 | name = "PowerPC 405EX2 Rev. C"; 377 | break; 378 | case 0x12911472: 379 | name = "PowerPC 405EXR1 Rev. D"; 380 | break; 381 | case 0x12911470: 382 | name = "PowerPC 405EXR2 Rev. D"; 383 | break; 384 | case 0x12911475: 385 | name = "PowerPC 405EX1 Rev. D"; 386 | break; 387 | case 0x12911473: 388 | name = "PowerPC 405EX2 Rev. D"; 389 | break; 390 | case 0x40120440: 391 | name = "PowerPC 440GP Rev. B"; 392 | break; 393 | case 0x40120481: 394 | name = "PowerPC 440GP Rev. C"; 395 | break; 396 | case 0x42221850: 397 | name = "PowerPC 440EP Rev. A"; 398 | break; 399 | case 0x422218D3: 400 | name = "PowerPC 440EP Rev. B or 440GR Rev. A"; 401 | break; 402 | case 0x422218D4: 403 | name = "PowerPC 440EP Rev. C or 440GR Rev. B"; 404 | break; 405 | case 0x216218D0: 406 | name = "PowerPC 440EPX1 Rev. A or 440GRX1 Rev. A"; 407 | break; 408 | case 0x216218D4: 409 | name = "PowerPC 440EPX2 Rev. A or 440GRX2 Rev. A"; 410 | break; 411 | case 0x51B21850: 412 | name = "PowerPC 440GX Rev. A"; 413 | break; 414 | case 0x51B21851: 415 | name = "PowerPC 440GX Rev. B"; 416 | break; 417 | case 0x51B21892: 418 | name = "PowerPC 440GX Rev. C"; 419 | break; 420 | case 0x51B21894: 421 | name = "PowerPC 440GX Rev. F"; 422 | break; 423 | case 0x53221850: 424 | name = "PowerPC 440SP_6 Rev. AB"; 425 | break; 426 | case 0x53321850: 427 | name = "PowerPC 440SP Rev. AB"; 428 | break; 429 | case 0x53221891: 430 | name = "PowerPC 440SP_6 Rev. C"; 431 | break; 432 | case 0x53321891: 433 | name = "PowerPC 440SP Rev. C"; 434 | break; 435 | case 0x53421890: 436 | name = "PowerPC 440SPe_6 Rev. A"; 437 | break; 438 | case 0x53521890: 439 | name = "PowerPC 440SPe Rev. A"; 440 | break; 441 | case 0x53421891: 442 | name = "PowerPC 440SPe_6 Rev. B"; 443 | break; 444 | case 0x53521891: 445 | name = "PowerPC 440SPe Rev. B"; 446 | break; 447 | case 0x130218A2: 448 | name = "PowerPC 460EX_SE Rev. A"; 449 | break; 450 | case 0x130218A3: 451 | name = "PowerPC 460EX Rev. A"; 452 | break; 453 | case 0x130218A4: 454 | name = "PowerPC 460EX Rev. B"; 455 | break; 456 | case 0x130218A0: 457 | name = "PowerPC 460GT_SE Rev. A"; 458 | break; 459 | case 0x130218A1: 460 | name = "PowerPC 460GT Rev. A"; 461 | break; 462 | case 0x130218A5: 463 | name = "PowerPC 460GT Rev. B"; 464 | break; 465 | case 0x13541800: 466 | name = "PowerPC 460SX Rev. A"; 467 | break; 468 | case 0x13541801: 469 | name = "PowerPC 460SX Rev. A_V1"; 470 | break; 471 | case 0x13541802: 472 | name = "PowerPC 460GX Rev. A"; 473 | break; 474 | case 0x13541803: 475 | name = "PowerPC 460GX Rev. A_V1"; 476 | break; 477 | case 0x12C41C80: 478 | name = "PowerPC APM821XX Rev. A"; 479 | break; 480 | case 0x00010000: 481 | name = "PowerPC 601"; 482 | break; 483 | case 0x00050000: 484 | name = "PowerPC 602"; 485 | break; 486 | case 0x00030000: 487 | name = "PowerPC 603"; 488 | break; 489 | case 0x00060000: 490 | name = "PowerPC 603e"; 491 | break; 492 | case 0x00070000: 493 | name = "PowerPC 603ev"; 494 | break; 495 | case 0x00071000: 496 | name = "PowerPC 603r"; 497 | break; 498 | case 0x00040000: 499 | name = "PowerPC 604"; 500 | break; 501 | case 0x00090000: 502 | name = "PowerPC 604e"; 503 | break; 504 | case 0x000A0000: 505 | name = "PowerPC 604r"; 506 | break; 507 | case 0x00140000: 508 | name = "PowerPC 620"; 509 | break; 510 | case 0x00080000: 511 | name = "PowerPC 740/750"; 512 | break; 513 | case 0x10080000: 514 | name = "PowerPC 740P/750P"; 515 | break; 516 | case 0x000C0000: 517 | name = "PowerPC 7400"; 518 | break; 519 | case 0x800C0000: 520 | name = "PowerPC 7410"; 521 | break; 522 | case 0x80000000: 523 | name = "PowerPC 7450"; 524 | break; 525 | case 0x80200000: 526 | name = "PowerPC 85xx"; 527 | break; 528 | case 0x80210000: 529 | name = "PowerPC 85xx Rev. 1.0"; 530 | break; 531 | case 0x80220000: 532 | name = "PowerPC 85xx Rev. 1.0"; 533 | break; 534 | case 0x80040000: 535 | name = "PowerPC 86xx"; 536 | break; 537 | case 0x7ff21912: 538 | name = "PowerPC VIRTEX5"; 539 | break; 540 | case 0x00500000: 541 | name = "PowerPC 821/832/850/860"; 542 | break; 543 | case 0x00810100: 544 | name = "PowerPC 8240/8240/8260"; 545 | break; 546 | case 0x00810101: 547 | name = "PowerPC 8260_HIP3"; 548 | break; 549 | case 0x80811014: 550 | name = "PowerPC 8260_HIP4"; 551 | break; 552 | case 0x80822011: 553 | name = "PowerPC 5200/8260_HIP7"; 554 | break; 555 | case 0x80822013: 556 | name = "PowerPC 8260_HIP7R1"; 557 | break; 558 | case 0x80822014: 559 | name = "PowerPC 5200B/8260_HIP7RA"; 560 | break; 561 | 562 | default: 563 | name = "Unknown"; 564 | break; 565 | } 566 | 567 | printf("CPU: %s", name.c_str()); 568 | 569 | clockSpeed(); 570 | 571 | printf(" (ID: %0X)", processorVersion); 572 | } 573 | } 574 | 575 | void clockSpeed() 576 | { 577 | float speed = (float)detection::gestalt(gestaltProcClkSpeed); 578 | if (speed != NULL) 579 | { 580 | if (speed < 1024.0) 581 | { 582 | printf(" %0.2fHz", speed); 583 | } 584 | else if (speed < 1048576.0) 585 | { 586 | printf(" %0.2fKHz", speed / 1024.0); 587 | } 588 | else if (speed < 1073741824.0) 589 | { 590 | printf(" %0.2fMHz", speed / 1048576.0); 591 | } 592 | else if (speed < 1099511627776.0) 593 | { 594 | printf(" %0.2fGHz", speed / 1073741824.0); 595 | } 596 | else if (speed < 1125899906842624.0) 597 | { 598 | printf(" %0.2fTHz", speed / 1099511627776.0); 599 | } 600 | else 601 | { 602 | printf(" %0.2fPHz", speed / 1125899906842624.0); 603 | } 604 | printf(" (%0.2f)", speed); 605 | } 606 | } 607 | void model() 608 | { 609 | int ver = os_version(); 610 | 611 | long sys; 612 | if (ver >= 0x605) 613 | { 614 | sys = detection::gestalt(gestaltMachineType); 615 | } 616 | else 617 | { 618 | SysEnvRec rec; 619 | SysEnvirons(1, &rec); 620 | sys = rec.machineType; 621 | // The result we get near perfectly maps to the modern one, with some exceptions. 622 | if (sys == 1) 623 | { 624 | sys = -1; 625 | } 626 | else if (sys == 2) 627 | { 628 | sys = 2; 629 | } 630 | else 631 | { 632 | sys -= 2; 633 | } 634 | } 635 | if (sys != NULL) 636 | { 637 | // We're supposed to be able to use GetIndString. This does not work, presumably because they stopped updating the index, but they did give us all the numbers in the last header file. 638 | const char *name = NULL; 639 | unsigned char *name2 = NULL; 640 | switch (sys) 641 | { 642 | case 0: 643 | name = "Macintosh 128k"; 644 | break; 645 | case 1: 646 | name = "Macintosh Classic"; 647 | break; 648 | case 2: 649 | name = "Macintosh XL"; 650 | break; 651 | case 3: 652 | name = "Macintosh 512K"; 653 | break; 654 | 655 | case 4: 656 | name = "Macintosh Plus"; 657 | break; 658 | case 5: 659 | name = "Macintosh SE"; 660 | break; 661 | case 6: 662 | name = "Macintosh II"; 663 | break; 664 | case 7: 665 | name = "Macintosh IIx"; 666 | break; 667 | 668 | case 8: 669 | name = "Macintosh IIcx"; 670 | break; 671 | case 9: 672 | name = "Macintosh SE030"; 673 | break; 674 | case 10: 675 | name = "Macintosh Portable"; 676 | break; 677 | case 11: 678 | name = "Macintosh IIci"; 679 | break; 680 | 681 | case 12: 682 | name = "Power Macintosh 8100/120"; 683 | break; 684 | case 13: 685 | name = "Macintosh IIfx"; 686 | break; 687 | case 17: 688 | name = "Macintosh Classic"; 689 | break; 690 | case 18: 691 | name = "Macintosh IIsi"; 692 | break; 693 | 694 | case 19: 695 | name = "Macintosh LC"; 696 | break; 697 | case 20: 698 | name = "Macintosh Quadra 900"; 699 | break; 700 | case 21: 701 | name = "PowerBook 170"; 702 | break; 703 | case 22: 704 | name = "Macintosh Quadra 700"; 705 | break; 706 | 707 | case 23: 708 | name = "Classic II"; 709 | break; 710 | case 24: 711 | name = "PowerBook 100"; 712 | break; 713 | case 25: 714 | name = "PowerBook 140"; 715 | break; 716 | case 26: 717 | name = "Macintosh Quadra950"; 718 | break; 719 | 720 | case 27: 721 | name = "Macintosh LCIII or Performa 450"; 722 | break; 723 | 724 | case 29: 725 | name = "PowerBook Duo 210"; 726 | break; 727 | case 30: 728 | name = "Macintosh Centris650"; 729 | break; 730 | 731 | case 32: 732 | name = "PowerBook Duo 230"; 733 | break; 734 | case 33: 735 | name = "PowerBook 180"; 736 | break; 737 | case 34: 738 | name = "PowerBook 160"; 739 | break; 740 | case 35: 741 | name = "Macintosh Quadra800"; 742 | break; 743 | 744 | case 36: 745 | name = "Macintosh Quadra650"; 746 | break; 747 | case 37: 748 | name = "Macintosh LCII"; 749 | break; 750 | case 38: 751 | name = "PowerBook Duo 250"; 752 | break; 753 | case 39: 754 | name = "Apple Macintosh WGS 9150/80"; 755 | break; 756 | 757 | case 40: 758 | name = "Power Macintosh 8100/110 or Apple Macintosh WGS 8110"; 759 | break; 760 | case 41: 761 | name = "Power Macintosh 52x0 or 5300"; 762 | break; 763 | case 42: 764 | name = "Power Macintosh 6200 or Performa 6300"; 765 | break; 766 | case 44: 767 | name = "Macintosh IIvi"; 768 | break; 769 | case 45: 770 | name = "Macintosh IIvm or Performa 600"; 771 | break; 772 | case 47: 773 | name = "Power Macintosh 7100/80"; 774 | break; 775 | case 48: 776 | name = "Macintosh IIvx"; 777 | break; 778 | 779 | case 49: 780 | name = "Macintosh Color Classic or Performa 250"; 781 | break; 782 | case 50: 783 | name = "PowerBook 165c"; 784 | break; 785 | case 52: 786 | name = "Macintosh Centris610"; 787 | break; 788 | 789 | case 53: 790 | name = "Macintosh Quadra610"; 791 | break; 792 | case 54: 793 | name = "PowerBook 145"; 794 | break; 795 | case 55: 796 | name = "Power Macintosh 8100/100"; 797 | break; 798 | case 56: 799 | name = "Macintosh LC520"; 800 | break; 801 | 802 | case 57: 803 | name = "Apple Macintosh WGS 9150/120"; 804 | break; 805 | case 58: 806 | name = "Power Macintosh 6400 or Performa 6400 or Performa 6360"; 807 | break; 808 | 809 | case 60: 810 | name = "Macintosh Centris660AV or Quadra660AV"; 811 | break; 812 | case 62: 813 | name = "Performa 46x"; 814 | break; 815 | case 65: 816 | name = "Power Macintosh 8100/80 or Apple Macintosh WGS 8150/80"; 817 | break; 818 | case 67: 819 | name = "Power Macintosh 9x00"; 820 | break; 821 | case 68: 822 | name = "Power Macintosh 7x00 or Apple Macintosh WGS 8550"; 823 | break; 824 | case 69: 825 | name = "Power Macintosh 8x00"; 826 | break; 827 | case 71: 828 | name = "PowerBook 180c"; 829 | break; 830 | case 72: 831 | name = "PowerBook 520 or 520c or 540 or 540c"; 832 | break; 833 | case 74: 834 | name = "Power Macintosh 5400"; 835 | break; 836 | case 75: 837 | name = "Power Macintosh 6100/60 or Apple Macintosh WGS 6150/60"; 838 | break; 839 | case 77: 840 | name = "PowerBook Duo 270c"; 841 | break; 842 | case 78: 843 | name = "Macintosh Quadra840AV"; 844 | break; 845 | case 80: 846 | name = "Performa 550"; 847 | break; 848 | case 84: 849 | name = "PowerBook 165"; 850 | break; 851 | 852 | case 85: 853 | name = "PowerBook 190"; 854 | break; 855 | case 88: 856 | name = "Macintosh TV"; 857 | break; 858 | case 89: 859 | name = "Macintosh LC475 or Performa 47x"; 860 | break; 861 | 862 | case 92: 863 | name = "Macintosh LC575"; 864 | break; 865 | case 94: 866 | name = "Macintosh Quadra605"; 867 | break; 868 | case 98: 869 | name = "Macintosh Quadra630"; 870 | break; 871 | case 99: 872 | name = "Macintosh LC580 or Performa 580"; 873 | break; 874 | case 100: 875 | name = "Power Macintosh 6100/66 or Apple Macintosh WGS 6150/66"; 876 | break; 877 | case 102: 878 | name = "PowerBook Duo 280"; 879 | break; 880 | case 103: 881 | name = "PowerBook Duo 280c"; 882 | break; 883 | case 104: 884 | name = "Power Macintosh LC475 or Power Macintosh Performa 47x"; 885 | break; 886 | case 105: 887 | name = "Power Macintosh LC575 or Power Macintosh Performa 57x"; 888 | break; 889 | case 106: 890 | name = "Power Macintosh Quadra 630 or Power Macintosh LC630 or Performa 63x"; 891 | break; 892 | case 108: 893 | name = "Power Macintosh 7200"; 894 | break; 895 | case 109: 896 | name = "Power Macintosh 7300"; 897 | break; 898 | case 112: 899 | name = "Power Macintosh 7100/66"; 900 | break; 901 | case 115: 902 | name = "PowerBook 150"; 903 | break; 904 | case 116: 905 | name = "Power Macintosh Quadra 700"; 906 | break; 907 | case 117: 908 | name = "Power Macintosh Quadra 900"; 909 | break; 910 | case 118: 911 | name = "Power Macintosh Quadra 950"; 912 | break; 913 | case 119: 914 | name = "Power Macintosh Centris 610"; 915 | break; 916 | 917 | case 120: 918 | name = "Power Macintosh Centris 650"; 919 | break; 920 | case 121: 921 | name = "Power Macintosh Quadra 610"; 922 | break; 923 | case 122: 924 | name = "Power Macintosh Quadra 650"; 925 | break; 926 | case 123: 927 | name = "Power Macintosh Quadra 800"; 928 | break; 929 | 930 | case 124: 931 | name = "PowerBook Duo 2300"; 932 | break; 933 | case 126: 934 | name = "PowerBook 500 PPC Upgrade"; 935 | break; 936 | case 128: 937 | name = "PowerBook 5300"; 938 | break; 939 | case 310: 940 | name = "PowerBook 1400"; 941 | break; 942 | case 306: 943 | name = "PowerBook 3400"; 944 | break; 945 | case 307: 946 | name = "PowerBook 2400"; 947 | break; 948 | case 312: 949 | name = "PowerBook G3 Series"; 950 | break; 951 | case 313: 952 | name = "PowerBook G3"; 953 | break; 954 | case 314: 955 | name = "PowerBook G3 Series 2"; 956 | break; 957 | case 406: 958 | name = "New World"; 959 | break; 960 | case 510: 961 | name = "Power Macintosh G3"; 962 | break; 963 | case 512: 964 | name = "Power Macintosh 5500 or Macintosh 20th Anniversary"; 965 | break; 966 | case 513: 967 | name = "Power Macintosh 6500"; 968 | break; 969 | case 514: 970 | name = "Power Macintosh 4400/160"; 971 | break; 972 | case 515: 973 | name = "Power Macintosh 4400"; 974 | break; 975 | default: 976 | GetIndString(name2, -16395, sys); 977 | break; 978 | } 979 | if (name != NULL) 980 | { 981 | printf("Model: %s (ID: %0.2f)", name, sys); 982 | } 983 | else 984 | { 985 | printf("Model: %s (ID: %0.2f)", name2, sys); 986 | } 987 | } 988 | return; 989 | } 990 | } 991 | -------------------------------------------------------------------------------- /src/detection/disk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "functions.hpp" 7 | 8 | #define _FSDispatch 0xA060 9 | 10 | namespace detection 11 | { 12 | #ifdef FOR_PPC 13 | pascal OSErr __PBXGetVolInfoSync(XVolumeParamPtr paramBlock) 14 | { 15 | enum 16 | { 17 | kXGetVolInfoSelector = 0x0012, /* Selector for XGetVolInfo */ 18 | 19 | uppFSDispatchProcInfo = kRegisterBased | REGISTER_RESULT_LOCATION(kRegisterD0) | RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(long))) /* trap word */ 20 | | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(long))) /* selector */ 21 | | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr))) 22 | }; 23 | 24 | return (CallOSTrapUniversalProc(NGetTrapAddress(_FSDispatch, OSTrap), 25 | uppFSDispatchProcInfo, 26 | _FSDispatch, 27 | kXGetVolInfoSelector, 28 | paramBlock)); 29 | } 30 | OSErr HGetVInfo(short volReference, 31 | StringPtr volName, 32 | short *vRefNum, 33 | unsigned long *freeBytes, 34 | unsigned long *totalBytes) 35 | { 36 | HParamBlockRec pb; 37 | unsigned long allocationBlockSize; 38 | unsigned short numAllocationBlocks; 39 | unsigned short numFreeBlocks; 40 | VCB *theVCB; 41 | Boolean vcbFound; 42 | OSErr result; 43 | 44 | pb.volumeParam.ioVRefNum = volReference; 45 | pb.volumeParam.ioNamePtr = volName; 46 | pb.volumeParam.ioVolIndex = 0; 47 | result = PBHGetVInfoSync(&pb); 48 | 49 | if (result == noErr) 50 | { 51 | 52 | *vRefNum = pb.volumeParam.ioVRefNum; 53 | allocationBlockSize = (unsigned long)pb.volumeParam.ioVAlBlkSiz; 54 | 55 | vcbFound = false; 56 | theVCB = (VCB *)(GetVCBQHdr()->qHead); 57 | while ((theVCB != NULL) && !vcbFound) 58 | { 59 | 60 | if (theVCB->vcbSigWord == 0x4244) 61 | { 62 | if (theVCB->vcbVRefNum == *vRefNum) 63 | { 64 | vcbFound = true; 65 | } 66 | } 67 | 68 | if (!vcbFound) 69 | { 70 | theVCB = (VCB *)(theVCB->qLink); 71 | } 72 | } 73 | 74 | if (theVCB != NULL) 75 | { 76 | 77 | numAllocationBlocks = (unsigned short)theVCB->vcbNmAlBlks; 78 | numFreeBlocks = (unsigned short)theVCB->vcbFreeBks; 79 | } 80 | else 81 | { 82 | 83 | numAllocationBlocks = (unsigned short)pb.volumeParam.ioVNmAlBlks; 84 | numFreeBlocks = (unsigned short)pb.volumeParam.ioVFrBlk; 85 | } 86 | 87 | *freeBytes = numFreeBlocks * allocationBlockSize; 88 | *totalBytes = numAllocationBlocks * allocationBlockSize; 89 | } 90 | 91 | return (result); 92 | } 93 | OSErr XGetVInfo(short volReference, 94 | StringPtr volName, 95 | short *vRefNum, 96 | UnsignedWide *freeBytes, 97 | UnsignedWide *totalBytes) 98 | { 99 | OSErr result; 100 | long response; 101 | XVolumeParam pb; 102 | 103 | if ((Gestalt(gestaltFSAttr, &response) == noErr) && ((response & (1L << gestaltFSSupports2TBVols)) != 0)) 104 | { 105 | 106 | pb.ioVRefNum = volReference; 107 | pb.ioNamePtr = volName; 108 | pb.ioXVersion = 0; 109 | pb.ioVolIndex = 0; 110 | result = __PBXGetVolInfoSync(&pb); 111 | if (result == noErr) 112 | { 113 | 114 | *vRefNum = pb.ioVRefNum; 115 | 116 | *totalBytes = (UnsignedWide)pb.ioVTotalBytes; 117 | *freeBytes = (UnsignedWide)pb.ioVFreeBytes; 118 | } 119 | } 120 | else 121 | { 122 | 123 | result = HGetVInfo(volReference, volName, vRefNum, &freeBytes->lo, &totalBytes->lo); 124 | if (result == noErr) 125 | { 126 | 127 | totalBytes->hi = 0; 128 | freeBytes->hi = 0; 129 | } 130 | } 131 | return (result); 132 | } 133 | #endif 134 | std::vector driveNumbers; 135 | std::vector drive_numbers() 136 | { 137 | return driveNumbers; 138 | }; 139 | short disk_num() 140 | { 141 | 142 | OSErr err = 0; 143 | 144 | for (short i = 3; i < 31; i++) 145 | { 146 | unsigned char *volName; 147 | short vRefNum; 148 | long freeBytes; 149 | err = GetVInfo(i, volName, &vRefNum, &freeBytes); 150 | if (err == 0) 151 | { 152 | driveNumbers.push_back(i); 153 | } 154 | } 155 | 156 | return driveNumbers.size(); 157 | } 158 | 159 | OSErr get_name(short i, std::string *res, HVolumeParam *io) 160 | { 161 | OSErr err; 162 | unsigned char *volName; 163 | short vRefNum; 164 | long freeBytes; 165 | 166 | err = GetVInfo(i, volName, &vRefNum, &freeBytes); 167 | if (err != 0) 168 | { 169 | return err; 170 | } 171 | 172 | HParamBlockRec sts = { 173 | .volumeParam = { 174 | .ioCompletion = NULL, 175 | .ioVolIndex = vRefNum, 176 | }}; 177 | err = PBHGetVInfo(&sts, false); 178 | if (err != 0) 179 | { 180 | return err; 181 | } 182 | *io = sts.volumeParam; 183 | 184 | auto n = volName; 185 | auto len = n[0]; 186 | auto str = std::string(); 187 | for (int j = 1; j < len + 1; j++) 188 | { 189 | str += n[j]; 190 | }; 191 | *res = str; 192 | return 0; 193 | } 194 | 195 | std::function disk(int listNum, short i) 196 | { 197 | return [listNum, i] 198 | { 199 | OSErr err; 200 | unsigned char *volName; 201 | short vRefNum; 202 | long freeBytes; 203 | 204 | err = GetVInfo(i, volName, &vRefNum, &freeBytes); 205 | if (err != 0) 206 | { 207 | printf("Error getting disk %d's name: %d", i, err); 208 | return; 209 | } 210 | 211 | HParamBlockRec sts = { 212 | .volumeParam = { 213 | .ioCompletion = NULL, 214 | .ioVolIndex = listNum, 215 | }}; 216 | err = PBHGetVInfo(&sts, false); 217 | if (err != 0) 218 | { 219 | return; 220 | } 221 | auto io = sts.volumeParam; 222 | 223 | auto n = volName; 224 | auto len = n[0]; 225 | auto str = std::string(); 226 | for (int j = 1; j < len + 1; j++) 227 | { 228 | str += n[j]; 229 | }; 230 | 231 | float allBlocks = ((float)(unsigned short)io.ioVNmAlBlks * (float)(unsigned long)io.ioVAlBlkSiz); 232 | float freeBlocks = (float)(unsigned long)freeBytes; 233 | printf("Disk %d: %s, ", listNum, str.c_str()); 234 | pprintMemory(allBlocks - freeBlocks); 235 | printf("/"); 236 | pprintMemory(allBlocks); 237 | printf(" ("); 238 | pprintMemory(freeBlocks); 239 | printf(" free) (ID: %d)", i); 240 | }; 241 | } 242 | /*std::function disk_below_91(int listNum, short i) 243 | { 244 | return [listNum, i] 245 | { 246 | HVolumeParam io; 247 | OSErr err; 248 | 249 | float freeBytes = -1.0f; 250 | float totalBytes = -1.0f; 251 | unsigned char *volName_; 252 | volName_ = (unsigned char *)"\0"; 253 | short vRefNum; 254 | UnsignedWide freeBytes_; 255 | UnsignedWide totalBytes_; 256 | err = XGetVInfo(i, volName_, &vRefNum, &freeBytes_, &totalBytes_); 257 | freeBytes = (float)freeBytes_.hi + (float)freeBytes_.lo; 258 | totalBytes = (float)totalBytes_.hi + (float)totalBytes_.lo; 259 | 260 | std::string volName; 261 | for (int i = 1; i < volName_[0] + 1; i++) 262 | { 263 | volName += volName_[i]; 264 | } 265 | if (err != 0) 266 | { 267 | printf("Error getting disk %d's size: %d", i, err); 268 | return; 269 | } 270 | else 271 | { 272 | printf("Disk %d: %s, ", listNum, volName.c_str()); 273 | pprintMemory(totalBytes - freeBytes); 274 | printf("/"); 275 | pprintMemory(totalBytes); 276 | printf(" ("); 277 | pprintMemory(freeBytes); 278 | printf(" free) (ID: %d)", i); 279 | } 280 | }; 281 | } 282 | std::function disk_above_91(int listNum, short i) 283 | { 284 | return [listNum, i] 285 | { 286 | OSErr err; 287 | unsigned char *volName; 288 | short vRefNum; 289 | long freeBytes; 290 | 291 | err = GetVInfo(i, volName, &vRefNum, &freeBytes); 292 | if (err != 0) 293 | { 294 | printf("Error getting disk %d's name: %d", i, err); 295 | return; 296 | } 297 | 298 | HParamBlockRec sts = { 299 | .volumeParam = { 300 | .ioCompletion = NULL, 301 | .ioVolIndex = listNum, 302 | }}; 303 | err = PBHGetVInfo(&sts, false); 304 | if (err != 0) 305 | { 306 | return; 307 | } 308 | auto io = sts.volumeParam; 309 | 310 | auto n = volName; 311 | auto len = n[0]; 312 | auto str = std::string(); 313 | for (int j = 1; j < len + 1; j++) 314 | { 315 | str += n[j]; 316 | }; 317 | 318 | float allBlocks = ((float)(unsigned short)io.ioVNmAlBlks * (float)(unsigned long)io.ioVAlBlkSiz); 319 | float freeBlocks = (float)(unsigned long)freeBytes; 320 | printf("Disk %d: %s, ", listNum, str.c_str()); 321 | pprintMemory(allBlocks - freeBlocks); 322 | printf("/"); 323 | pprintMemory(allBlocks); 324 | printf("* ("); 325 | pprintMemory(freeBlocks); 326 | printf(" free) (ID: %d)", i); 327 | }; 328 | } 329 | std::function disk(int listNum, short i) 330 | { 331 | long sys = detection::gestalt(gestaltSystemVersion); 332 | if (sys == NULL) 333 | { 334 | return [listNum, i] {}; 335 | } 336 | if (sys >= 0x910) 337 | { 338 | return disk_above_91(listNum, i); 339 | } 340 | else 341 | { 342 | return disk_below_91(listNum, i); 343 | } 344 | }*/ 345 | 346 | void disk_notice() 347 | { 348 | printf("* HFS+ disks not read properly on computers running 9.1+."); 349 | } 350 | } 351 | 352 | /* 353 | 354 | #include 355 | #include 356 | #include 357 | #include 358 | #include 359 | #include "functions.hpp" 360 | 361 | namespace detection 362 | { 363 | OSErr HGetVInfo(short volReference, 364 | StringPtr volName, 365 | short *vRefNum, 366 | unsigned long *freeBytes, 367 | unsigned long *totalBytes) 368 | { 369 | HParamBlockRec pb; 370 | unsigned long allocationBlockSize; 371 | unsigned short numAllocationBlocks; 372 | unsigned short numFreeBlocks; 373 | VCB *theVCB; 374 | Boolean vcbFound; 375 | OSErr result; 376 | 377 | 378 | pb.volumeParam.ioVRefNum = volReference; 379 | pb.volumeParam.ioNamePtr = volName; 380 | pb.volumeParam.ioVolIndex = 0; 381 | result = PBHGetVInfoSync(&pb); 382 | 383 | if (result == noErr) 384 | { 385 | 386 | 387 | *vRefNum = pb.volumeParam.ioVRefNum; 388 | allocationBlockSize = (unsigned long)pb.volumeParam.ioVAlBlkSiz; 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | vcbFound = false; 401 | theVCB = (VCB *)(GetVCBQHdr()->qHead); 402 | while ((theVCB != NULL) && !vcbFound) 403 | { 404 | 405 | 406 | if (theVCB->vcbSigWord == 0x4244) 407 | { 408 | if (theVCB->vcbVRefNum == *vRefNum) 409 | { 410 | vcbFound = true; 411 | } 412 | } 413 | 414 | if (!vcbFound) 415 | { 416 | theVCB = (VCB *)(theVCB->qLink); 417 | } 418 | } 419 | 420 | if (theVCB != NULL) 421 | { 422 | 423 | 424 | numAllocationBlocks = (unsigned short)theVCB->vcbNmAlBlks; 425 | numFreeBlocks = (unsigned short)theVCB->vcbFreeBks; 426 | } 427 | else 428 | { 429 | 430 | 431 | numAllocationBlocks = (unsigned short)pb.volumeParam.ioVNmAlBlks; 432 | numFreeBlocks = (unsigned short)pb.volumeParam.ioVFrBlk; 433 | } 434 | 435 | 436 | *freeBytes = numFreeBlocks * allocationBlockSize; 437 | *totalBytes = numAllocationBlocks * allocationBlockSize; 438 | } 439 | 440 | return (result); 441 | } 442 | OSErr XGetVInfo(short volReference, 443 | StringPtr volName, 444 | short *vRefNum, 445 | UnsignedWide *freeBytes, 446 | UnsignedWide *totalBytes) 447 | { 448 | OSErr result; 449 | long response; 450 | XVolumeParam pb; 451 | 452 | 453 | if ((Gestalt(gestaltFSAttr, &response) == noErr) && ((response & (1L << gestaltFSSupports2TBVols)) != 0)) 454 | { 455 | 456 | pb.ioVRefNum = volReference; 457 | pb.ioNamePtr = volName; 458 | pb.ioXVersion = 0; 459 | pb.ioVolIndex = 0; 460 | result = PBXGetVolInfoSync(&pb); 461 | if (result == noErr) 462 | { 463 | 464 | 465 | *vRefNum = pb.ioVRefNum; 466 | 467 | 468 | *totalBytes = (UnsignedWide)pb.ioVTotalBytes; 469 | *freeBytes = (UnsignedWide)pb.ioVFreeBytes; 470 | } 471 | } 472 | else 473 | { 474 | 475 | 476 | 477 | result = HGetVInfo(volReference, volName, vRefNum, &freeBytes->lo, &totalBytes->lo); 478 | if (result == noErr) 479 | { 480 | 481 | totalBytes->hi = 0; 482 | freeBytes->hi = 0; 483 | } 484 | } 485 | return (result); 486 | } 487 | std::vector driveNumbers; 488 | std::vector drive_numbers() 489 | { 490 | return driveNumbers; 491 | }; 492 | short disk_num() 493 | { 494 | OSErr err = 0; 495 | for (short i = 3; i < 31; i++) 496 | { 497 | unsigned char *volName; 498 | short vRefNum; 499 | long freeBytes; 500 | err = GetVInfo(i, volName, &vRefNum, &freeBytes); 501 | if (err == 0) 502 | { 503 | driveNumbers.push_back(i); 504 | } 505 | } 506 | 507 | return driveNumbers.size(); 508 | } 509 | std::function disk(int listNum, short i) 510 | { 511 | return [listNum, i] 512 | { 513 | OSErr err; 514 | unsigned char *volName; 515 | short vRefNum; 516 | long freeBytesOld; 517 | 518 | err = GetVInfo(i, volName, &vRefNum, &freeBytesOld); 519 | if (err != 0) 520 | { 521 | printf("Error getting disk %d's name: %d", i, err); 522 | return; 523 | } 524 | 525 | HParamBlockRec sts = { 526 | .volumeParam = { 527 | .ioCompletion = NULL, 528 | .ioVolIndex = listNum, 529 | }}; 530 | err = PBHGetVInfo(&sts, false); 531 | if (err != 0) 532 | { 533 | return; 534 | } 535 | auto io = sts.volumeParam; 536 | 537 | auto n = volName; 538 | auto len = n[0]; 539 | auto str = std::string(); 540 | for (int j = 1; j < len + 1; j++) 541 | { 542 | str += n[j]; 543 | }; 544 | 545 | UnsignedWide freeBytes; 546 | UnsignedWide totalBytes; 547 | 548 | err = XGetVInfo(vRefNum, volName, &vRefNum, &freeBytes, &totalBytes); 549 | 550 | if (err != 0) 551 | { 552 | return; 553 | } 554 | float allBlocks = (float)(totalBytes.lo) + (float)(totalBytes.hi); 555 | float freeBlocks = (float)(freeBytes.lo) + (float)(freeBytes.hi); 556 | 557 | printf("Disk %d: %s, ", listNum, str.c_str()); 558 | pprintMemory(allBlocks - freeBlocks); 559 | printf("/"); 560 | pprintMemory(allBlocks); 561 | printf(" ("); 562 | pprintMemory(freeBlocks); 563 | printf(" free) (ID: %d)", i); 564 | }; 565 | } 566 | } 567 | */ -------------------------------------------------------------------------------- /src/detection/functions.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include "functions.hpp" 6 | 7 | namespace detection 8 | { 9 | std::vector> functions() 10 | { 11 | int ver = os_version(); 12 | 13 | auto vec = std::vector>(); 14 | 15 | if (detection::name_avaliable()) 16 | { 17 | vec.push_back(std::function(detection::name)); 18 | vec.push_back(std::function(detection::line)); 19 | } 20 | 21 | vec.push_back(std::function(detection::os)); 22 | if (ver >= 0x605) 23 | { 24 | vec.push_back(std::function(detection::rom)); 25 | } 26 | vec.push_back(std::function(detection::cpu)); 27 | vec.push_back(std::function(detection::model)); 28 | if (ver >= 0x605) 29 | { 30 | vec.push_back(std::function(detection::memory)); 31 | } 32 | else 33 | { 34 | 35 | vec.push_back(std::function(detection::fpu)); 36 | vec.push_back(std::function(detection::color)); 37 | vec.push_back(std::function(detection::keyboard)); 38 | } 39 | // As far as I know there was only one non-PPC laptop and it has a lead-acid battery that nobody even has working, so we'll be lazy and remove it. Feel free to correct me. 40 | #ifdef FOR_PPC 41 | if (detection::has_battery()) 42 | { 43 | vec.push_back(std::function(detection::battery)); 44 | } 45 | #endif 46 | 47 | #ifdef FOR_PPC 48 | // Disk support. 49 | if (ver < 0x810) 50 | { 51 | short disks = detection::disk_num(); 52 | auto numbers = detection::drive_numbers(); 53 | for (int i = 0; i < disks; i++) 54 | { 55 | vec.push_back(std::function(detection::disk(i + 1, numbers[i]))); 56 | } 57 | } 58 | #endif 59 | return vec; 60 | } 61 | } -------------------------------------------------------------------------------- /src/detection/functions.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FUNCTIONS 2 | #define FUNCTIONS 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace detection 9 | { 10 | long gestalt(OSType l); 11 | int os_version(); 12 | bool has_battery(); 13 | bool name_avaliable(); 14 | void memory(); 15 | void cpu(); 16 | void model(); 17 | void os(); 18 | void rom(); 19 | void battery(); 20 | void gpu(); 21 | void name(); 22 | void line(); 23 | void pprintMemory(float memSize); 24 | void pprintMemoryMB(float memSize); 25 | void disk_notice(); 26 | bool is_utf8(const char *string); 27 | 28 | void fpu(); 29 | void color(); 30 | void keyboard(); 31 | 32 | std::vector drive_numbers(); 33 | 34 | short disk_num(); 35 | std::function disk(int listNum, short i); 36 | 37 | // void uptime(); 38 | std::vector> 39 | functions(); 40 | } 41 | #endif -------------------------------------------------------------------------------- /src/detection/gestalt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace detection 5 | { 6 | long gestalt(OSType l) 7 | { 8 | long res = NULL; 9 | auto err = Gestalt(l, &res); 10 | if (err != 0) 11 | { 12 | switch (err) 13 | { 14 | case -5500: 15 | printf("_SysEnvirons trap not present"); 16 | break; 17 | case -5501: 18 | printf("negative number used in verReqNo"); 19 | break; 20 | case -5502: 21 | printf("verReqNo version not handled by this system."); 22 | break; 23 | } 24 | } 25 | return res; 26 | }; 27 | 28 | } -------------------------------------------------------------------------------- /src/detection/gpu.cpp: -------------------------------------------------------------------------------- 1 | #include "functions.hpp" 2 | #include 3 | #include 4 | 5 | extern "C" 6 | { 7 | void gpu_raw() 8 | { 9 | #ifdef FOR_PPC 10 | const GLubyte *vendor = glGetString(GL_VENDOR); // Returns the vendor 11 | const GLubyte *renderer = glGetString(GL_RENDERER); // Returns a hint to the model 12 | printf("%s, %s", vendor, renderer); 13 | #endif 14 | } 15 | } 16 | namespace detection 17 | { 18 | void gpu() 19 | { 20 | gpu_raw(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/detection/memory.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "functions.hpp" 5 | #include "Processes.h" 6 | namespace detection 7 | { 8 | void memory() 9 | { 10 | 11 | // failed attempt to get accumulated ram usage 12 | /*OSErr err = 0; 13 | ProcessSerialNumber ptr; 14 | unsigned long usedMem; 15 | while (err != -600) 16 | { 17 | err = GetNextProcess(&ptr); 18 | 19 | ProcessInfoRecPtr info; 20 | OSErr err2 = GetProcessInformation(&ptr, info); 21 | if (err2 != 50) 22 | { 23 | usedMem += (info->processSize - (long)info->processLocation) - info->processFreeMem; 24 | } 25 | }*/ 26 | auto memsize = detection::gestalt(gestaltLogicalRAMSize); 27 | if (memsize != NULL) 28 | { 29 | printf("Memory: "); 30 | pprintMemory(memsize); 31 | } 32 | 33 | return; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/detection/misc.cpp: -------------------------------------------------------------------------------- 1 | #include "functions.hpp" 2 | namespace detection 3 | { 4 | bool is_utf8(const char *string) 5 | { 6 | if (!string) 7 | return true; 8 | 9 | const unsigned char *bytes = (const unsigned char *)string; 10 | int num; 11 | 12 | while (*bytes != 0x00) 13 | { 14 | if ((*bytes & 0x80) == 0x00) 15 | { 16 | // U+0000 to U+007F 17 | num = 1; 18 | } 19 | else if ((*bytes & 0xE0) == 0xC0) 20 | { 21 | // U+0080 to U+07FF 22 | num = 2; 23 | } 24 | else if ((*bytes & 0xF0) == 0xE0) 25 | { 26 | // U+0800 to U+FFFF 27 | num = 3; 28 | } 29 | else if ((*bytes & 0xF8) == 0xF0) 30 | { 31 | // U+10000 to U+10FFFF 32 | num = 4; 33 | } 34 | else 35 | return false; 36 | 37 | bytes += 1; 38 | for (int i = 1; i < num; ++i) 39 | { 40 | if ((*bytes & 0xC0) != 0x80) 41 | return false; 42 | bytes += 1; 43 | } 44 | } 45 | 46 | return true; 47 | } 48 | 49 | void pprintMemory(float memsize) 50 | { 51 | if (memsize < 1024.0f) 52 | { 53 | printf("%0.2fB", memsize); 54 | } 55 | else if (memsize < 1048576.0f) 56 | { 57 | printf("%0.2fKB", memsize / 1024.0f); 58 | } 59 | else if (memsize < 1073741824.0f) 60 | { 61 | printf("%0.2fMB", memsize / 1048576.0f); 62 | } 63 | else if (memsize < 1099511627776.0f) 64 | { 65 | printf("%0.2fGB", memsize / 1073741824.0f); 66 | } 67 | else if (memsize < 1125899906842624.0f) 68 | { 69 | printf("%0.2fTB", memsize / 1099511627776.0f); 70 | } 71 | else 72 | { 73 | printf("%0.2fPB", memsize / 1125899906842624.0f); 74 | } 75 | } 76 | 77 | void pprintMemoryMB(float memsize) 78 | { 79 | if (memsize < 1000.0f) 80 | { 81 | printf("%0.2fB", memsize); 82 | } 83 | else if (memsize < 1000000.0f) 84 | { 85 | printf("%0.2fKB", memsize / 1000.0f); 86 | } 87 | else if (memsize < 1000000000.0f) 88 | { 89 | printf("%0.2fMB", memsize / 1000000.0f); 90 | } 91 | else if (memsize < 1000000000000.0f) 92 | { 93 | printf("%0.2fGB", memsize / 1000000000.0f); 94 | } 95 | else if (memsize < 1000000000000000.0f) 96 | { 97 | printf("%0.2fTB", memsize / 1000000000000.0f); 98 | } 99 | else if (memsize < 1000000000000000000.0f) 100 | { 101 | printf("%0.2fPB", memsize / 1000000000000000); 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /src/detection/os.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "functions.hpp" 6 | namespace detection 7 | { 8 | int os_version() 9 | { 10 | 11 | SysEnvRec rec; 12 | SysEnvirons(1, &rec); 13 | return rec.systemVersion; 14 | } 15 | void os() 16 | { 17 | int sys = os_version(); 18 | static char buf[100]; 19 | std::string version; 20 | const int len = std::snprintf(buf, sizeof(buf), "%lx", sys); 21 | version = std::string(buf, len); 22 | std::string version_final = std::string(); 23 | 24 | for (int i = 0; i < version.length(); i++) 25 | { 26 | version_final += version[i]; 27 | if (i <= version.length() - 2) 28 | { 29 | version_final += "."; 30 | } 31 | } 32 | printf("OS Version: %s", version_final.c_str()); 33 | } 34 | } -------------------------------------------------------------------------------- /src/detection/rom.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "functions.hpp" 4 | 5 | namespace detection 6 | { 7 | void rom() 8 | { 9 | long sys = detection::gestalt(gestaltROMVersion); 10 | if (sys != NULL) 11 | { 12 | static char buf[100]; 13 | std::string version; 14 | const int len = std::snprintf(buf, sizeof(buf), "%lu", sys); 15 | printf("ROM Version: %s", buf); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/detection/user.cpp: -------------------------------------------------------------------------------- 1 | #include "functions.hpp" 2 | #include 3 | #include 4 | 5 | namespace detection 6 | { 7 | int driveAmount = -1; 8 | bool name_avaliable() 9 | { 10 | HParamBlockRec pb = HParamBlockRec{ 11 | .objParam = ObjParam{ 12 | .ioCompletion = NULL, 13 | .ioVRefNum = 0, 14 | }}; 15 | OSErr err = PBHGetLogInInfo(&pb, false); 16 | if (err != 0) 17 | { 18 | return false; 19 | }; 20 | 21 | // We might get a false positive, indicitive by the resulting string not being valid name. Double check to make sure it's valid. 22 | auto n = pb.objParam.ioNamePtr; 23 | auto len = n[0]; 24 | auto str = std::string(); 25 | for (int i = 1; i < len + 1; i++) 26 | { 27 | str += n[i]; 28 | }; 29 | return is_utf8(str.c_str()); 30 | } 31 | 32 | std::string name_str() 33 | { 34 | std::string name; 35 | HParamBlockRec pb = HParamBlockRec{ 36 | .objParam = ObjParam{ 37 | .ioCompletion = NULL, 38 | .ioVRefNum = 0, 39 | }}; 40 | OSErr err = PBHGetLogInInfo(&pb, false); 41 | if (err == 0) 42 | { 43 | auto n = pb.objParam.ioNamePtr; 44 | auto len = n[0]; 45 | auto str = std::string(); 46 | for (int i = 1; i < len + 1; i++) 47 | { 48 | name += n[i]; 49 | }; 50 | } 51 | 52 | auto obj = HParamBlockRec{ 53 | .objParam = ObjParam{ 54 | .ioCompletion = NULL, 55 | .ioNamePtr = pb.objParam.ioNamePtr, 56 | .ioVRefNum = pb.objParam.ioVRefNum, 57 | .ioObjNamePtr = pb.objParam.ioObjNamePtr, 58 | .ioObjID = pb.objParam.ioObjID, 59 | }}; 60 | obj.objParam.ioObjType = 4; 61 | err = PBHMapName(&obj, false); 62 | if (err == 0) 63 | { 64 | name += "@"; 65 | auto n = obj.objParam.ioObjNamePtr; 66 | auto len = n[0]; 67 | auto str = std::string(); 68 | for (int i = 1; i < len + 1; i++) 69 | { 70 | name += n[i]; 71 | }; 72 | } 73 | return name; 74 | } 75 | void line() 76 | { 77 | auto n = name_str(); 78 | for (int i = 0; i < n.length(); i++) 79 | { 80 | printf("-"); 81 | } 82 | } 83 | void name() 84 | { 85 | printf("%s", name_str().c_str()); 86 | } 87 | } -------------------------------------------------------------------------------- /src/detection/xpostcode/CPUDevice.cpp: -------------------------------------------------------------------------------- 1 | #include "CPUDevice.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | CPUDeviceList CPUDevice::gCPUDeviceList; 8 | bool CPUDevice::gHasBeenInitialized = false; 9 | int CPUDevice::gCPUCount = 0; 10 | 11 | void ThrowIfNULL_AC(void *what, char *hit) 12 | { 13 | if (what == NULL) 14 | { 15 | printf("%s was null!\n", hit); 16 | getchar(); 17 | exit(1); 18 | return; 19 | } 20 | }; 21 | void ThrowIfOSErr_AC(OSErr what) 22 | { 23 | if (what != 0) 24 | { 25 | printf("Error: %d\n", what); 26 | getchar(); 27 | exit(1); 28 | return; 29 | } 30 | }; 31 | void CPUDevice::Initialize() 32 | { 33 | if (gHasBeenInitialized) 34 | return; 35 | 36 | gHasBeenInitialized = true; 37 | 38 | // We iterate through, and collected all entries with a device type "cpu" 39 | 40 | RegEntryIter cookie; 41 | RegEntryID entry; 42 | Boolean done = false; 43 | RegEntryIterationOp iterOp = kRegIterDescendants; 44 | OSStatus err = RegistryEntryIterateCreate(&cookie); 45 | 46 | while (true) 47 | { 48 | err = RegistryEntryIterate(&cookie, iterOp, &entry, &done); 49 | if (!done && (err == noErr)) 50 | { 51 | RegPropertyValueSize propSize; 52 | err = RegistryPropertyGetSize(&entry, kDeviceTypeProperty, &propSize); 53 | if (err == noErr) 54 | { 55 | char *deviceType = NewPtr(propSize + 1); 56 | ThrowIfNULL_AC(deviceType, "deviceType"); 57 | ThrowIfOSErr_AC(RegistryPropertyGet(&entry, kDeviceTypeProperty, deviceType, &propSize)); 58 | deviceType[propSize] = '\0'; 59 | if (!strcmp(deviceType, "cpu")) 60 | { 61 | gCPUDeviceList.push_back(entry); 62 | } 63 | DisposePtr(deviceType); 64 | } 65 | RegistryEntryIDDispose(&entry); 66 | } 67 | else 68 | { 69 | break; 70 | } 71 | iterOp = kRegIterContinue; 72 | } 73 | RegistryEntryIterateDispose(&cookie); 74 | } 75 | 76 | CPUDevice::~CPUDevice() 77 | { 78 | #ifdef __MACH__ 79 | #else 80 | RegistryEntryIDDispose(fRegEntryID); 81 | #endif 82 | } 83 | 84 | #define kCPUIDPropName "cpu#" 85 | #define kCPUVersionPropName "cpu-version" 86 | 87 | CPUDevice::CPUDevice(REG_ENTRY_TYPE regEntry) 88 | { 89 | 90 | ThrowIfNULL_AC(regEntry, "regEntry"); 91 | RegistryEntryIDCopy(regEntry, &fRegEntryIDStorage); 92 | fRegEntryID = &fRegEntryIDStorage; 93 | 94 | // OFAliases::AliasFor(fRegEntryID, fOpenFirmwareName, fShortOpenFirmwareName); 95 | 96 | RegPropertyValueSize propSize; 97 | 98 | OSErr err; 99 | 100 | fCPUNumber = 0; 101 | err = RegistryPropertyGetSize(fRegEntryID, kCPUIDPropName, &propSize); 102 | if ((err == noErr) && (propSize == sizeof(fCPUNumber))) 103 | { 104 | ThrowIfOSErr_AC(RegistryPropertyGet(regEntry, kCPUIDPropName, &fCPUNumber, &propSize)); 105 | } 106 | 107 | fCPUVersion = 0; 108 | err = RegistryPropertyGetSize(fRegEntryID, kCPUVersionPropName, &propSize); 109 | if ((err == noErr) && (propSize == sizeof(fCPUVersion))) 110 | { 111 | ThrowIfOSErr_AC(RegistryPropertyGet(fRegEntryID, kCPUVersionPropName, &fCPUVersion, &propSize)); 112 | } 113 | 114 | #if qLogging 115 | gLogFile << "CPU#: " << fCPUNumber << endl_AC; 116 | gLogFile << "OpenFirmwareName: " << fOpenFirmwareName << endl_AC; 117 | gLogFile << "ShortOpenFirmwareName: " << fShortOpenFirmwareName << endl_AC; 118 | gLogFile << "CPUVersion: " << fCPUVersion << endl_AC; 119 | #endif 120 | } 121 | 122 | std::vector CPUDevice::GetCPUS() 123 | { 124 | return gCPUDeviceList; 125 | } 126 | -------------------------------------------------------------------------------- /src/detection/xpostcode/CPUDevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | CPUDevice 4 | ========= 5 | 6 | The function of this class is to maintain a list of all the name registry 7 | entries that are CPUs. 8 | 9 | */ 10 | 11 | #ifndef __CPUDEVICE_H__ 12 | #define __CPUDEVICE_H__ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #define kCPUIDPropName "cpu#" 19 | #define kCPUVersionPropName "cpu-version" 20 | #define kDeviceTypeProperty "device_type" 21 | 22 | typedef RegEntryID *REG_ENTRY_TYPE; 23 | class CPUDevice; 24 | 25 | typedef std::vector CPUDeviceList; 26 | 27 | void ThrowIfNULL_AC(void *what, char *hit); 28 | void ThrowIfOSErr_AC(OSErr what); 29 | class CPUDevice 30 | { 31 | 32 | public: 33 | static void Initialize(); 34 | 35 | static std::vector GetCPUS(); 36 | 37 | static int getCPUCount() { return gCPUCount; } 38 | 39 | ~CPUDevice(); 40 | 41 | RegEntryID fRegEntryIDStorage; 42 | REG_ENTRY_TYPE fRegEntryID; 43 | char fOpenFirmwareName[256]; 44 | char fShortOpenFirmwareName[256]; 45 | UInt32 fCPUNumber; 46 | UInt32 fCPUVersion; 47 | 48 | CPUDevice(REG_ENTRY_TYPE regEntry); 49 | 50 | private: 51 | static CPUDeviceList gCPUDeviceList; 52 | static int gCPUCount; 53 | static bool gHasBeenInitialized; 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/logo.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #pragma once 5 | 6 | static std::vector apple_logo = {" 'c. ", 7 | " ,xNMM. ", 8 | " .OMMMMo ", 9 | " OMMM0, ", 10 | " .;loddo:' loolloddol;. ", 11 | " cKMMMMMMMMMMNWMMMMMMMMMM0: ", 12 | " .KMMMMMMMMMMMMMMMMMMMMMMMWd. ", 13 | " XMMMMMMMMMMMMMMMMMMMMMMMX. ", 14 | ";MMMMMMMMMMMMMMMMMMMMMMMM: ", 15 | ":MMMMMMMMMMMMMMMMMMMMMMMM: ", 16 | ".MMMMMMMMMMMMMMMMMMMMMMMMX. ", 17 | " kMMMMMMMMMMMMMMMMMMMMMMMMWd. ", 18 | " .XMMMMMMMMMMMMMMMMMMMMMMMMMMk ", 19 | " .XMMMMMMMMMMMMMMMMMMMMMMMMK. ", 20 | " kMMMMMMMMMMMMMMMMMMMMMMd ", 21 | " ;KMMMMMMMWXXWMMMMMMMk. ", 22 | " .cooc,. .,coo:. "}; 23 | -------------------------------------------------------------------------------- /src/os9fetch.cpp: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include 3 | #include "logo.hpp" 4 | 5 | #include "detection/functions.hpp" 6 | #include "console/Console.hpp" 7 | #include "console/ConsoleWindow.hpp" 8 | 9 | void main_below_4(); 10 | void main_above_4(); 11 | 12 | int main() 13 | { 14 | retro::InitConsole(); 15 | 16 | auto functions = detection::functions(); 17 | std::vector buf = std::vector(); 18 | 19 | for (int i = 0; i < apple_logo.size(); i++) 20 | { 21 | auto logo = apple_logo[i].c_str(); 22 | printf("%s ", logo); 23 | if (i < functions.size()) 24 | { 25 | functions[i](); 26 | } 27 | printf("\n"); 28 | } 29 | 30 | retro::Console::currentInstance->ReadLine(); 31 | return 0; 32 | } 33 | 34 | void main_below_4() 35 | { 36 | retro::InitConsole(); 37 | 38 | for (int i = 0; i < apple_logo.size(); i++) 39 | { 40 | auto logo = apple_logo[i]; 41 | 42 | retro::Console::currentInstance->write(logo.c_str(), logo.size()); 43 | retro::Console::currentInstance->write("\n", 1); 44 | } 45 | 46 | retro::Console::currentInstance->ReadLine(); 47 | } 48 | 49 | void main_above_4() 50 | { 51 | retro::InitConsole(); 52 | 53 | auto functions = detection::functions(); 54 | std::vector buf = std::vector(); 55 | 56 | for (int i = 0; i < apple_logo.size(); i++) 57 | { 58 | auto logo = apple_logo[i].c_str(); 59 | printf("%s ", logo); 60 | if (i < functions.size()) 61 | { 62 | functions[i](); 63 | } 64 | printf("\n"); 65 | } 66 | 67 | retro::Console::currentInstance->ReadLine(); 68 | } --------------------------------------------------------------------------------