pax_global_header00006660000000000000000000000064131455450470014522gustar00rootroot0000000000000052 comment=5b48c130651c75c37aaa1c1f2557b8c27fd72ae4 drawterm-20170818/000077500000000000000000000000001314554504700136235ustar00rootroot00000000000000drawterm-20170818/.gitignore000066400000000000000000000000741314554504700156140ustar00rootroot00000000000000drawterm.log state state.old state.journal drawterm *.o *.a drawterm-20170818/.travis.yml000066400000000000000000000025011314554504700157320ustar00rootroot00000000000000language: c env: global: # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # via the "travis encrypt" command using the project repo's public key - secure: "XV94I8e37QmVwdIEXukEtvkq0PG15L53ZuZprr03HczsTAouILpn83uhDXtjV2srBIGIMKpJcUjRS0XcUV1CwWb9mEIkh8bJcyzWH+9BnQfJTrkq3D5odV/xUBWut54OlcSk6+nkq1yUMA0z5x+xJAwN3XxEIPLN+aTqezG6lMM9afVg80FMpFyoOUV7EybsUlbRygxbuy8APBsRkNfqIGRZRnYNg0HnQJh/WhfXrREPTsr/Cp8WlagU0VeG3BNT8ChhH4ysHQdKaIHVbMyg+PLmhsHCc3KObZSm76xCxd62+qPlosGiqQQEvuhZHBe+UW6cs2qTMBWRkW0Z/e2svKsyKqTNCm/INyQn6PHq1CMWgH26fR3MrYdBQ7+BrejjxBlAXQPUrdbNyES6ccTdhoUW/OQincGZaHalzedRWzH7Q+WW+tgELUjmV7iRcKeBw9npeM6n4LfqEE96P9Oqx/rVgZ2ov2G14GAKjtwy4BFdwYv/hyDK1GV+uqpdcFPr9WYrU6D/JRqvHpjnhumlGgsI4MqPtZYjSxJNy8M8lnk5urp7TyDy0BC4FcPRkvZH3eYZUr5Da/0HwjRIxonIBrVT7MzNy3GHZjl1mQ5Y/EuuOd5Nhy9Gq2i08xdfn5pp5VdT2/CLwwwoOC09VlNaK7/E48bo34AVBIkHfR/shPE=" - CONF=unix before_install: - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- addons: coverity_scan: project: name: "0intro/drawterm" description: "Build submitted via Travis CI" notification_email: 0intro@gmail.com build_command_prepend: "make clean" build_command: "make" branch_pattern: master script: - make clean - make drawterm-20170818/9ball.ico000066400000000000000000000221561314554504700153300ustar00rootroot00000000000000h6 @@(F( @AAA aaa000QQQ(((888IIIXXXhhh$$$444<<<MMM---DDDTTT[[[^^^ddd&&&***222666:::>>>FFFKKKOOOVVV!!!###%%%''')))...///111333555777;;;===???BBBCCCGGGHHHLLLNNNPPPRRRSSSWWWZZZ___```bbbeee F'HE''FFF'34 4IH'FF'MP7M6JH'F'7;XWW )P!KI'FIhD0eZ<;:)O''aU9@d\j.g,$? Cc??( @@@@ ```000PPPppp(((888HHHXXXhhhwww$$$,,,444<<<DDDLLLTTT\\\ddd{{{sss"""&&&***...222666:::>>>BBBFFFJJJNNNRRRVVVZZZ^^^bbbfffnnnyyy!!!###%%%''')))+++---///111333555777999;;;===???AAACCCEEEGGGIIIKKKMMMOOOQQQSSSUUUWWWYYY[[[]]]___aaaccceeegggoootttvvvzzz kk""m k"""""kk""@ """k"""""""kk"ok"""""kkkk"""""kkm>mnn@m""kk"""""k"iBsCuuuC$qonm"kk""""kkCE%zGGGz%EvusBm"kk"""k"{}&&&}G%EsBnm"k"""km$HL &Hzxso@"k"""kB NNN(L&H{zECqn"k""k"u:[QO&}Gxuqn"k""k$9Y\*Q J{%$n"k"k@,^`72SQ)OL&%$n"k"kvU;`PPP7N &%q@"kkE.65RK')N &%uBmkkm 7~wwybVSO &{Esn"k"|RprF X,VTOHGvqmk"~<d6# TONLJ}%Cnkm,'PtehjjY-Z X,T &GBkE!g=7]X,TJ}x$mF9/XQO zsD3U=pb V)L&GCC P403p+]Z,SJ{uIlKFf?2-XO(J{% MgA8/]Z,*JcW+b11a_[ J_a11a_/]-OS1111a_/]-*_1a_/]- ,S aZXT,]_/][Z,--Z(@@@@ ```000PPPppp(((888HHHXXXhhhxxx $$$,,,444<<<DDDLLLTTT\\\dddlllttt|||"""&&&***...222666:::>>>BBBFFFJJJNNNRRRVVVZZZ^^^bbbfffjjjnnnrrrvvvzzz~~~ !!!###%%%''')))+++---///111333555777999;;;===???AAACCCEEEGGGIIIKKKMMMOOOQQQSSSUUUWWWYYY[[[]]]___aaaccceeegggiiikkkoooqqqsssuuuwww}}}~B""~""""""" ~"""""""""""""""DzB""""""""""""""""""""""J """""""""""""""""""""""""""B~"""""""""""""""""""""""""""""z""""""""""""""""""""""""B|""""""""""""""""""""""""""""""$~"""DDDDDDDD""""""""""""""""""""""~"FFFFFFFDD""""""""""""""""""""~DF$HHHHH$$FFD""""""""""""""""""BHHH$F"""""""""""""""" FJ&&&&&&&&JH$FD"""""""""""""""$z$LLLL&JHF""""""""""""""&NNNNNNNL&&JHF""""""""""""BLN(PP((NNL&JHFD""""""""""""@PP PP((NLJH$""""""""""""HP RRR P(NLJFD""""""""""~(P R**T**R P(NL&H$FD""""""""""B&**TTTT**R P(&J"""""""""""@ R*\\VVVVVT**RP(NL&"""""""""BP$ \qi9¬,,,,VVT*R PNH$F"""""""" ig3 5\XXXX,VVT* (N&JH$F""""""""3c1aaX,VT*RPL&JH$F"""""""BF.3e_///au\ZZX,VT* P(NL&JH$F"""""L3ceo...ZX,VT*R P(NL&JH$"""""""P1/1fGy{{?}}fd2b `0^\.,VT(N&"_#>{yُxxyyx!6hf2b`0^\.ZR JHFDtIEkxxx In<2b`^.ZX,VTP(LDBO;{)܋1cpjf2b`^*RN$"a_s)sG'cvm2b `0\.ZX,V N&$FsEt9}KIxAqfd2 0^T*PDP\x)x5j[!_d2b `^\.ZX,R($%xyQ+ӽdb`0^VR (qCx#o<Yxٖ $(D 尞W^M@i ===/ŵ' mڵ !SHf$h2dϞ,A6u֢B.ž=KH~haZ|Hf%hW)I)PH0!!īH0&&o AOСC;RZ|fgEI)PU$8iҤL'RE;FN}'K-//pIP+ v%(5+yH EGGW4#vwxD2PϪR^#e|RD+Kɓ'+0a#0`K:u&uu,4;e<V)ĉ) lhh۷'{QӒVg4Jvl*ս@9R)"I 8zh6j(`=0-?g LN>VL),22ݻ7 p.HГ3nq'@y`JTL$85CK Y>@+g-@uP#""Hlȑ/i`Ϟ8B ƕ_灝%@ He0#F i4ja~1Ut4YIv@6B*ٰa*////2Y?Zz{}~=}?&?Y+TOHe0/BC&"t?!$wfǏ}9,?;ӟ]-S`-ʓ`u``XXunݺ~ ]mtkǏ[:yNם3He$@6|pz?An.>ټr{eiĶmۦ+>?J(z^POS`jCpyЖVH$ݼx߿ߔ؝R)@!C>x[cp2%9Y@4YQHg3ϮW,|3ʓ`!@*)^̑NR-K*Ϟ=Szj+7v 6tLIu59:vD$X?6 8%{?W?͏?, ܹMn ֭[ӢlӦM +}Lzo> 't&@ $40H_~ez-aUUUdEp&VKr#ر*޽[-[:$H)P^k59ZH`!@6h i}DD(?}ľ})@ pHBtJcǎP6HrbGe'OdgϞegΜaȑ#Ib; @͖fӟY_y"}JRfH}@???ZM )HdA" 1ܻw}YSwUֹs甯⪨>|؄e{aeeeԩSҥKڵkƍJʼr劒8 V*ߥ2hkgg$@y"sL}@KF*R H*ɀF˗/۷444K\TSy yi&>yDбׯ+$ڵK))}'J߮?W (Y8lg {gҢцa8FIĕD]ƍ*JH4BƎ9C2tH6f;W}<]Sg04{N֕p=,PY rb9s& .U&5_}rڵݻw'_|Em ƍaG [_h.o鯭R @ 5LgY6@}_ҝ;weG_~zVDBZ| ٱc<_*@_!H'rE@vvʕ\jU ~c~o MRKYID ӧO__;3O6}vhP*_ ./vMJV=C\>̢_uL>|8 pړ Q#%y曐"_~=̌Pd ko_G[X;A׭[ \g?\i&HFd4MPx̐Aj@gM~ɏ?8믃3|gC-a.0U~cWZ6@f],Y2b5Y/f(f(8*B7+)}ECW' g<޽{C=qqo, uq# Nu O]n aZr4:}:9I`lѣGCgv8v`\*.o_g6MH @hGvOq굸IyPn*Rd.0L]i7 zE-r~%ٚ= gvϦ1 q_\ڰzåfu@`P5# Z~sQ)k_v à5p~cRߔu:)bE\ub 4GAb9@  ?㹣q P$^k{饗vlٔwJu\#te:\,B'|2/|R \ =\!J @Uz'k农SԨ=*tSly.WxtxA,̀ HJH NЂiѓ([`MpN~9ϯ 1RTϺ7+(_fM˵дfȩ1°`@@@uA(21Aڪ%qu as~o~S߮/WK&t855{4غ@Fa(7Gw8d @ڡ@g='´~G_gWTS4qJ*%iBٳ' N ^ z6b0_KmoI{4=rojϺQJKl՟ruƂwatoIAf!"PSt" .T& _7ks5-_ZHc>ܛ\ @:8@tute)*q*RVo΃B6A#VSnKcoH_RruEɂ瀁r޽&Y2)`4gfH DlXY12hЌa}m J}_Iuwd{,To`@FbHAa!A|-z!Ma'Y& ?>rn-x5>j_mK4755r-$}e3G,H )8@ C8yGw-iG4zzgAGN}E_)7Wj|_mCѼ;t̢WCN.0 AK$=RJ!r]A΂.,TrvfCt~mծ{,Vr  @ AaRb@I _9\tT ǽ.KR/5<⺟ƩoGV8]Y,t?O^cۋ/ꁂ øA B=ܜK#eY)Ok={6\KR/~vG\S>\vbY  {I;*X`^\ z]RTc M[S>\vme~1BOn pkmn ^5 T[JyS17=lohQ]vm\bEX,|@.oߞA#Jqvĉ'"Xwjqܓtx9u_*-z74U.W,Z/\ uzj4F Bȑ#~85r@-5z.s^z]JwK)o7G7=Eru̢/] H:LM2"ġ qD9CC`L} ǏPZݒK%XL^7Y,v p`yƯcǂKܿ\!uB@H-5$< ۫_.͹\o⎯mz ).WvX,~Hky/`b<7H8ARc\!1uB`hd15\s֭I圞^պT;&jzh~˖-Ap64%,tMϝ; xƍ͛7!10EpC:<38.ˁ/Uu}wl mzشio\ub<`a-@JNJ $5 E" 6HB_;w̦%赹KR17k`28\EaETX` xʕy >H*P@s{y:.< ˥%WJyoĎhs.W7m Xt{G!\!aqSj~%w z}դ9~Deҥ?.BEͲ@ 8SN7Z #=dzK+ zCY.WwMhY k׮ӧ'/^ [C9C-m-a$4`DF7BAt%EZԭ.?+~ҍ;F Vޜ;O}t9$y~Ɠ}g!(ܔ a!ofooy* 6S"󉔝)<_酵>n/J~rs+rA/!9@ K Jj2y);)<)jW|(?7/\. ='h M!q-Lv.٤lu}ʛ&4T]gB?nMdhbcB|/-Vw^r񃐧a aCd%A)B)C)Dm1MzayvקkbZ*7'Ee5hPb2#=d'} ARGH B 6JJ!R):);W{%=_E~F!O *+ l)A&B-C]rt &;l ks/mU+V C$ijMRq#?%0'lnҨl6%T*Rf5(E(e((c&8\‹mqW|QU_Z2 ?Q@P єoamq%>[77o(!$B)-A"\l ef&;)<__X)!2>; i(3.Ǜb, )BKJ!Z¤gU6=Aҏ60$I@M &J/sKC+9[_Bn>oJ8  el1_U*=Vn."sđ ] "2B' ޺ZHBHW?8 )B)C)D)$N WzK-w~ l!S:R\]s&(鹪Q9"p-V!)FWdgKzj/'<珐*CR)DSda׹dg^R.>~ssu#$rrJJJ!J)F^+eg^KOa}}5Oy!$!ģEe#yMx](GU7BHj6e((8dׅ“WcGH[e|"rٙ! V,[do.;;;\%f$2`)C੅csI/m|ƒ SpKR8 /-^ ;<>.>{Ƃ& §_ '&&~)}ZXXޞ!=拡wJb{TjżacrrܻA%KU!U{ccc_?T[gĆܫVo*_>oUZXB!B!B!B!@PUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUځCA_ Lz@IENDB`drawterm-20170818/9ball.rc000066400000000000000000000000471314554504700151550ustar00rootroot00000000000000IDI_ICON1 ICON DISCARDABLE "9ball.ico" drawterm-20170818/CONTRIBUTORS000066400000000000000000000005311314554504700155020ustar00rootroot00000000000000# This file lists people who have contributed code to # drawterm, as recorded by the Mercurial and CVS logs. # The list is incomplete but a start. # My thanks to the people not listed here too. Andrey Mirtchovski Erik Quanstrom David du Colombier <0intro@gmail.com> Russ Cox Yaroslav drawterm-20170818/LICENSE000066400000000000000000000276301314554504700146400ustar00rootroot00000000000000Copyright (c) 2005 Lucent Technologies Portions Copyright (c) 2005 Russ Cox, MIT The Plan 9 software is provided under the terms of the Lucent Public License, Version 1.02, reproduced below. =================================================================== Lucent Public License Version 1.02 THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 1. DEFINITIONS "Contribution" means: a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original Program, and b. in the case of each Contributor, i. changes to the Program, and ii. additions to the Program; where such changes and/or additions to the Program were added to the Program by such Contributor itself or anyone acting on such Contributor's behalf, and the Contributor explicitly consents, in accordance with Section 3C, to characterization of the changes and/or additions as Contributions. "Contributor" means LUCENT and any other entity that has Contributed a Contribution to the Program. "Distributor" means a Recipient that distributes the Program, modifications to the Program, or any part thereof. "Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. "Original Program" means the original version of the software accompanying this Agreement as released by LUCENT, including source code, object code and documentation, if any. "Program" means the Original Program and Contributions or any part thereof "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. 2. GRANT OF RIGHTS a. Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. b. Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. The patent license granted by a Contributor shall also apply to the combination of the Contribution of that Contributor and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license granted by a Contributor shall not apply to (i) any other combinations which include the Contribution, nor to (ii) Contributions of other Contributors. No hardware per se is licensed hereunder. c. Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. d. Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. 3. REQUIREMENTS A. Distributor may choose to distribute the Program in any form under this Agreement or under its own license agreement, provided that: a. it complies with the terms and conditions of this Agreement; b. if the Program is distributed in source code or other tangible form, a copy of this Agreement or Distributor's own license agreement is included with each copy of the Program; and c. if distributed under Distributor's own license agreement, such license agreement: i. effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; ii. effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; and iii. states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party. B. Each Distributor must include the following in a conspicuous location in the Program: Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved. C. In addition, each Contributor must identify itself as the originator of its Contribution in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. Also, each Contributor must agree that the additions and/or changes are intended to be a Contribution. Once a Contribution is contributed, it may not thereafter be revoked. 4. COMMERCIAL DISTRIBUTION Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Distributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for Contributors. Therefore, if a Distributor includes the Program in a commercial product offering, such Distributor ("Commercial Distributor") hereby agrees to defend and indemnify every Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively"Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Distributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Distributor in writing of such claim, and b) allow the Commercial Distributor to control, and cooperate with the Commercial Distributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. For example, a Distributor might include the Program in a commercial product offering, Product X. That Distributor is then a Commercial Distributor. If that Commercial Distributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Distributor's responsibility alone. Under this section, the Commercial Distributor would have to defend claims against the Contributors related to those performance claims and warranties, and if a court requires any Contributor to pay any damages as a result, the Commercial Distributor must pay those damages. 5. NO WARRANTY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 6. DISCLAIMER OF LIABILITY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. EXPORT CONTROL Recipient agrees that Recipient alone is responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries). 8. GENERAL If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. LUCENT may publish new versions (including revisions) of this Agreement from time to time. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. No one other than LUCENT has the right to modify this Agreement. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. drawterm-20170818/Make.config000066400000000000000000000000501314554504700156620ustar00rootroot00000000000000AUDIO=none include $(ROOT)/Make.$(CONF) drawterm-20170818/Make.irix000066400000000000000000000007551314554504700154040ustar00rootroot00000000000000# Unix PTHREAD= # for Mac #PTHREAD=-pthread AR=ar AS=as ASFLAGS=-c -mips3 RANLIB=true X11=/usr/X11R6 #CC=gcc #CFLAGS=-Wall -Wno-missing-braces -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -I$(X11)/include -D_THREAD_SAFE $(PTHREAD) -O2 CC=cc CFLAGS=-g -O2 -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -I$(X11)/include -DIRIX O=o OS=posix GUI=x11 LDADD=-L$(X11)/lib -lX11 -g -lpthread LDFLAGS=$(PTHREAD) TARG=drawterm MAKE=gmake all: default libmachdep.a: (cd posix-mips && $(MAKE)) drawterm-20170818/Make.osx000066400000000000000000000006561314554504700152420ustar00rootroot00000000000000# Mac OS X PTHREAD= # for Mac AR=ar AS=as RANLIB=ranlib CC=gcc CFLAGS=-Wall -Wno-missing-braces -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -D_THREAD_SAFE $(PTHREAD) -O2 O=o OS=posix GUI=osx LDADD=-ggdb -framework Carbon -framework QuickTime LDFLAGS=$(PTHREAD) TARG=drawterm AUDIO=none all: default libmachdep.a: arch=`uname -m|sed 's/i.86/386/;s/Power Macintosh/power/;s/x86_64/amd64/'`; \ (cd posix-$$arch && make) drawterm-20170818/Make.osx-x11000066400000000000000000000006721314554504700156470ustar00rootroot00000000000000# Mac OS X PTHREAD= # for Mac AR=ar AS=as RANLIB=ranlib X11=/usr/X11R6 CC=gcc CFLAGS=-Wall -Wno-missing-braces -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -I$(X11)/include -D_THREAD_SAFE $(PTHREAD) -O2 O=o OS=posix GUI=x11 LDADD=-L$(X11)/lib -lX11 -ggdb LDFLAGS=$(PTHREAD) TARG=drawterm AUDIO=none all: default libmachdep.a: arch=`uname -m|sed 's/i.86/386/;s/Power Macintosh/power/;s/x86_64/amd64/'`; \ (cd posix-$$arch && make) drawterm-20170818/Make.pthread000066400000000000000000000006451314554504700160560ustar00rootroot00000000000000# Unix #PTHREAD= # for Mac PTHREAD=-pthread -DPTHREAD AR=ar AS=no-as-here RANLIB=ranlib X11=/usr/X11R6 CC=gcc CFLAGS=-Wall -Wno-missing-braces -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -I$(X11)/include -D_THREAD_SAFE $(PTHREAD) -O2 O=o OS=posix GUI=x11 LDADD=-L$(X11)/lib64 -L$(X11)/lib -lX11 -ggdb LDFLAGS=$(PTHREAD) TARG=drawterm # AUDIO=none AUDIO=unix all: default libmachdep.a: (cd posix-port && make) drawterm-20170818/Make.sun000066400000000000000000000005711314554504700152320ustar00rootroot00000000000000# Sun-specific PTHREAD= AR=ar AS=as RANLIB=ranlib X11=/usr/X11R6 CC=cc CFLAGS=-xCC -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -g -D_THREAD_SAFE O=o OS=posix GUI=x11 LDADD=-L$(X11)/lib -lX11 -lrt -lpthread -lsocket -lnsl LDFLAGS= TARG=drawterm AUDIO=none all: default libmachdep.a: arch=`uname -m|sed 's/i.86/386/;s/Power Macintosh/power/'`; \ (cd posix-$$arch && make) drawterm-20170818/Make.unix000066400000000000000000000007721314554504700154130ustar00rootroot00000000000000# Unix #PTHREAD= # for Mac PTHREAD=-pthread AR=ar AS=as RANLIB=ranlib X11=/usr/X11R6 CC=gcc CFLAGS=-Wall -Wno-missing-braces -fno-strict-aliasing -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -I$(X11)/include -D_THREAD_SAFE $(PTHREAD) -O2 O=o OS=posix GUI=x11 LDADD=-L$(X11)/lib64 -L$(X11)/lib -lX11 -ggdb LDFLAGS=$(PTHREAD) TARG=drawterm # AUDIO=none AUDIO=unix all: default libmachdep.a: arch=`uname -m|sed 's/i.86/386/;s/Power Macintosh/power/; s/x86_64/amd64/'`; \ (cd posix-$$arch && make) drawterm-20170818/Make.win32000066400000000000000000000014721314554504700153700ustar00rootroot00000000000000# Windows via mingw32 # MING=mingw32- is necessary if you're cross-compiling # on another platform. Otherwise the binaries are just # named gcc, etc. MING=i686-w64-mingw32- #MING= AR=$(MING)ar CC=$(MING)gcc AS=$(MING)as RANLIB=$(MING)ranlib WINDRES=$(MING)windres CFLAGS=-Wall -Wno-missing-braces -I$(ROOT)/include -I$(ROOT) -I$(ROOT)/kern -c -D_X86_ -DIS_32 -DWINDOWS -DUNICODE -O2 O=o FS=fs-win32 IP=win32 OS=win32 GUI=win32 LDFLAGS=-mwindows LDADD=-lkernel32 -ladvapi32 -lgdi32 -lmpr -lwsock32 -lmsvcrt -lmingw32 TARG=drawterm.exe XOFILES=9ball.$O # Windows via MSVC #AR=??? #CC=cl #CFLAGS=-c -nologo -W3 -YX -Zi -MT -Zl -Iinclude -DWINDOWS #O=obj #FS=fs-win32 #IP=win32 #OS=win32 #GUI=win32 all: default # for root libmachdep.a: (cd win32-386; make) 9ball.$O: 9ball.rc 9ball.ico $(WINDRES) -i 9ball.rc -o 9ball.o drawterm-20170818/Makefile000066400000000000000000000022151314554504700152630ustar00rootroot00000000000000ROOT=. include Make.config OFILES=\ main.$O\ cpu.$O\ readcons.$O\ secstore.$O\ latin1.$O\ $(OS)-factotum.$O\ $(XOFILES)\ LIBS1=\ kern/libkern.a\ exportfs/libexportfs.a\ libauth/libauth.a\ libauthsrv/libauthsrv.a\ libsec/libsec.a\ libmp/libmp.a\ libmemdraw/libmemdraw.a\ libmemlayer/libmemlayer.a\ libdraw/libdraw.a\ gui-$(GUI)/libgui.a\ libc/libc.a\ libip/libip.a\ # stupid gcc LIBS=$(LIBS1) $(LIBS1) $(LIBS1) libmachdep.a default: $(TARG) $(TARG): $(OFILES) $(LIBS) $(CC) $(LDFLAGS) -o $(TARG) $(OFILES) $(LIBS) $(LDADD) %.$O: %.c $(CC) $(CFLAGS) $*.c clean: rm -f *.o */*.o */*.a *.a drawterm drawterm.exe kern/libkern.a: (cd kern; $(MAKE)) exportfs/libexportfs.a: (cd exportfs; $(MAKE)) libauth/libauth.a: (cd libauth; $(MAKE)) libauthsrv/libauthsrv.a: (cd libauthsrv; $(MAKE)) libmp/libmp.a: (cd libmp; $(MAKE)) libsec/libsec.a: (cd libsec; $(MAKE)) libmemdraw/libmemdraw.a: (cd libmemdraw; $(MAKE)) libmemlayer/libmemlayer.a: (cd libmemlayer; $(MAKE)) libdraw/libdraw.a: (cd libdraw; $(MAKE)) libc/libc.a: (cd libc; $(MAKE)) libip/libip.a: (cd libip; $(MAKE)) gui-$(GUI)/libgui.a: (cd gui-$(GUI); $(MAKE)) drawterm-20170818/README.md000066400000000000000000000022521314554504700151030ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/0intro/drawterm.svg?branch=master)](https://travis-ci.org/0intro/drawterm) [![Coverity Scan Build Status](https://scan.coverity.com/projects/drawterm/badge.svg)](https://scan.coverity.com/projects/drawterm) INSTALLATION -------------- To build on Unix, run CONF=unix make. To build on Solaris using Sun cc, run CONF=sun make. To build on Windows, you need Mingw. See http://www.mingw.org. Edit Make.config to uncomment the Windows section and comment out the rest. Then run CONF=win32 make. (You can download nmake from http://support.microsoft.com/default.aspx?scid=kb;en-us;Q132084 Rename it to make.exe and put it in your path somewhere. ) I haven't tested the Windows build on Windows itself. I cross-compile using mingw32 on Linux. SOURCE ------ Use Git: git clone https://github.com/0intro/drawterm In the Plan 9 distribution: /sys/src/cmd/unix/drawterm/ (sometimes out of date) HELP ---- Issue tracker: https://github.com/0intro/drawterm/issues TO DO: ------ - Should import latest /dev/draw to allow resize of window - Should copy 9term code and make console window a real 9term window instead. - Should implement /dev/label. drawterm-20170818/args.h000066400000000000000000000013051314554504700147270ustar00rootroot00000000000000extern char *argv0; #define ARGBEGIN for((argv0? 0: (argv0=*argv)),argv++,argc--;\ argv[0] && argv[0][0]=='-' && argv[0][1];\ argc--, argv++) {\ char *_args, *_argt;\ Rune _argc;\ _args = &argv[0][1];\ if(_args[0]=='-' && _args[1]==0){\ argc--; argv++; break;\ }\ _argc = 0;\ while(*_args && (_args += chartorune(&_argc, _args)))\ switch(_argc) #define ARGEND SET(_argt);USED(_argt); USED(_argc); USED(_args);}USED(argv); USED(argc); #define ARGF() (_argt=_args, _args="",\ (*_argt? _argt: argv[1]? (argc--, *++argv): 0)) #define ARGC() _argc #define EARGF(x) (_argt=_args, _args="",\ (*_argt? _argt: argv[1]? (argc--, *++argv): (x, (char*)0))) drawterm-20170818/cpu-bl.c000066400000000000000000000334461314554504700151630ustar00rootroot00000000000000/* * cpu.c - Make a connection to a cpu server * * Invoked by listen as 'cpu -R | -N service net netdir' * by users as 'cpu [-h system] [-c cmd args ...]' */ #include #include #include #include #include #include #include "args.h" #include "drawterm.h" #define Maxfdata 8192 #define MaxStr 128 static void fatal(int, char*, ...); static void usage(void); static void writestr(int, char*, char*, int); static int readstr(int, char*, int); static char *rexcall(int*, char*, char*); static char *keyspec = ""; static AuthInfo *p9any(int); #define system csystem static char *system; static int cflag; extern int dbg; static char *srvname = "ncpu"; static char *ealgs = "rc4_256 sha1"; /* message size for exportfs; may be larger so we can do big graphics in CPU window */ static int msgsize = Maxfdata+IOHDRSZ; /* authentication mechanisms */ static int netkeyauth(int); static int netkeysrvauth(int, char*); static int p9auth(int); static int srvp9auth(int, char*); char *authserver; typedef struct AuthMethod AuthMethod; struct AuthMethod { char *name; /* name of method */ int (*cf)(int); /* client side authentication */ int (*sf)(int, char*); /* server side authentication */ } authmethod[] = { { "p9", p9auth, srvp9auth,}, { "netkey", netkeyauth, netkeysrvauth,}, // { "none", noauth, srvnoauth,}, { nil, nil} }; AuthMethod *am = authmethod; /* default is p9 */ char *p9authproto = "p9any"; int setam(char*); void exits(char *s) { print("\ngoodbye\n"); for(;;) osyield(); } void usage(void) { fprint(2, "usage: drawterm [-a authserver] [-c cpuserver] [-s secstore] [-u user]\n"); exits("usage"); } int fdd; int mountfactotum(void) { int fd; if((fd = dialfactotum()) < 0) return -1; if(sysmount(fd, -1, "/mnt/factotum", MREPL, "") < 0){ fprint(2, "mount factotum: %r\n"); return -1; } if((fd = open("/mnt/factotum/ctl", OREAD)) < 0){ fprint(2, "open /mnt/factotum/ctl: %r\n"); return -1; } close(fd); return 0; } void cpumain(int argc, char **argv) { char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *err, *secstoreserver, *p, *s; int fd, ms, data; /* see if we should use a larger message size */ fd = open("/dev/draw", OREAD); if(fd > 0){ ms = iounit(fd); if(msgsize < ms+IOHDRSZ) msgsize = ms+IOHDRSZ; close(fd); } user = getenv("USER"); if(user == nil) user = readcons("user", nil, 0); secstoreserver = nil; authserver = getenv("auth"); if(authserver == nil) authserver = "lookout.cs.bell-labs.com"; system = getenv("cpu"); if(system == nil) system = "anna.cs.bell-labs.com"; ARGBEGIN{ case 'o': authserver = "plan9.bell-labs.com"; system = "plan9.bell-labs.com"; break; case 'a': authserver = EARGF(usage()); break; case 'c': system = EARGF(usage()); break; case 'd': dbg++; break; case 'e': ealgs = EARGF(usage()); if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) ealgs = nil; break; case 'C': cflag++; cmd[0] = '!'; cmd[1] = '\0'; while((p = ARGF()) != nil) { strcat(cmd, " "); strcat(cmd, p); } break; case 'k': keyspec = EARGF(usage()); break; case 'u': user = EARGF(usage()); break; case 's': secstoreserver = EARGF(usage()); break; default: usage(); }ARGEND; if(argc != 0) usage(); if(mountfactotum() < 0){ if(secstoreserver == nil) secstoreserver = authserver; if(havesecstore(secstoreserver, user)){ s = secstorefetch(secstoreserver, user, nil); if(s){ if(strlen(s) >= sizeof secstorebuf) sysfatal("secstore data too big"); strcpy(secstorebuf, s); } } } if((err = rexcall(&data, system, srvname))) fatal(1, "%s: %s", err, system); /* Tell the remote side the command to execute and where our working directory is */ if(cflag) writestr(data, cmd, "command", 0); if(getcwd(dat, sizeof(dat)) == 0) writestr(data, "NO", "dir", 0); else writestr(data, dat, "dir", 0); /* * Wait for the other end to execute and start our file service * of /mnt/term */ if(readstr(data, buf, sizeof(buf)) < 0) fatal(1, "waiting for FS: %r"); if(strncmp("FS", buf, 2) != 0) { print("remote cpu: %s", buf); exits(buf); } if(readstr(data, buf, sizeof buf) < 0) fatal(1, "waiting for remote export: %r"); if(strcmp(buf, "/") != 0){ print("remote cpu: %s" , buf); exits(buf); } write(data, "OK", 2); /* Begin serving the gnot namespace */ exportfs(data, msgsize); fatal(1, "starting exportfs"); } void fatal(int syserr, char *fmt, ...) { Fmt f; char *str; va_list arg; fmtstrinit(&f); fmtprint(&f, "cpu: "); va_start(arg, fmt); fmtvprint(&f, fmt, arg); va_end(arg); if(syserr) fmtprint(&f, ": %r"); fmtprint(&f, "\n"); str = fmtstrflush(&f); write(2, str, strlen(str)); exits(str); } char *negstr = "negotiating authentication method"; char bug[256]; char* rexcall(int *fd, char *host, char *service) { char *na; char dir[MaxStr]; char err[ERRMAX]; char msg[MaxStr]; int n; na = netmkaddr(host, "tcp", "17010"); if((*fd = dial(na, 0, dir, 0)) < 0) return "can't dial"; /* negotiate authentication mechanism */ if(ealgs != nil) snprint(msg, sizeof(msg), "%s %s", am->name, ealgs); else snprint(msg, sizeof(msg), "%s", am->name); writestr(*fd, msg, negstr, 0); n = readstr(*fd, err, sizeof err); if(n < 0) return negstr; if(*err){ werrstr(err); return negstr; } /* authenticate */ *fd = (*am->cf)(*fd); if(*fd < 0) return "can't authenticate"; return 0; } void writestr(int fd, char *str, char *thing, int ignore) { int l, n; l = strlen(str); n = write(fd, str, l+1); if(!ignore && n < 0) fatal(1, "writing network: %s", thing); } int readstr(int fd, char *str, int len) { int n; while(len) { n = read(fd, str, 1); if(n < 0) return -1; if(*str == '\0') return 0; str++; len--; } return -1; } static int readln(char *buf, int n) { int i; char *p; n--; /* room for \0 */ p = buf; for(i=0; isecret, ai->nsecret); if(ealgs == nil) return fd; /* exchange random numbers */ for(i = 0; i < 4; i++) key[i] = fastrand(); if(write(fd, key, 4) != 4) return -1; if(readn(fd, key+12, 4) != 4) return -1; /* scramble into two secrets */ sha1(key, sizeof(key), digest, nil); mksecret(fromclientsecret, digest); mksecret(fromserversecret, digest+10); /* set up encryption */ i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil); if(i < 0) werrstr("can't establish ssl connection: %r"); return i; } int authdial(char *net, char *dom) { int fd; fd = dial(netmkaddr(authserver, "tcp", "567"), 0, 0, 0); //print("authdial %d\n", fd); return fd; } static int getastickets(Ticketreq *tr, char *trbuf, char *tbuf) { int asfd, rv; char *dom; dom = tr->authdom; asfd = authdial(nil, dom); if(asfd < 0) return -1; rv = _asgetticket(asfd, trbuf, tbuf); close(asfd); return rv; } static int mkserverticket(Ticketreq *tr, char *authkey, char *tbuf) { int i; Ticket t; if(strcmp(tr->authid, tr->hostid) != 0) return -1; memset(&t, 0, sizeof(t)); memmove(t.chal, tr->chal, CHALLEN); strcpy(t.cuid, tr->uid); strcpy(t.suid, tr->uid); for(i=0; i= 0) return 0; return mkserverticket(tr, key, tbuf); } /* * prompt user for a key. don't care about memory leaks, runs standalone */ static Attr* promptforkey(char *params) { char *v; int fd; Attr *a, *attr; char *def; fd = open("/dev/cons", ORDWR); if(fd < 0) sysfatal("opening /dev/cons: %r"); attr = _parseattr(params); fprint(fd, "\n!Adding key:"); for(a=attr; a; a=a->next) if(a->type != AttrQuery && a->name[0] != '!') fprint(fd, " %q=%q", a->name, a->val); fprint(fd, "\n"); for(a=attr; a; a=a->next){ v = a->name; if(a->type != AttrQuery || v[0]=='!') continue; def = nil; if(strcmp(v, "user") == 0) def = getuser(); a->val = readcons(v, def, 0); if(a->val == nil) sysfatal("user terminated key input"); a->type = AttrNameval; } for(a=attr; a; a=a->next){ v = a->name; if(a->type != AttrQuery || v[0]!='!') continue; def = nil; if(strcmp(v+1, "user") == 0) def = getuser(); a->val = readcons(v+1, def, 1); if(a->val == nil) sysfatal("user terminated key input"); a->type = AttrNameval; } fprint(fd, "!\n"); close(fd); return attr; } /* * send a key to the mounted factotum */ static int sendkey(Attr *attr) { int fd, rv; char buf[1024]; fd = open("/mnt/factotum/ctl", ORDWR); if(fd < 0) sysfatal("opening /mnt/factotum/ctl: %r"); rv = fprint(fd, "key %A\n", attr); read(fd, buf, sizeof buf); close(fd); return rv; } int askuser(char *params) { Attr *attr; fmtinstall('A', _attrfmt); attr = promptforkey(params); if(attr == nil) sysfatal("no key supplied"); if(sendkey(attr) < 0) sysfatal("sending key to factotum: %r"); return 0; } AuthInfo* p9anyfactotum(int fd, int afd) { return auth_proxy(fd, askuser, "proto=p9any role=client %s", keyspec); } AuthInfo* p9any(int fd) { char buf[1024], buf2[1024], cchal[CHALLEN], *bbuf, *p, *dom, *u; char *pass; char tbuf[TICKETLEN+TICKETLEN+AUTHENTLEN], trbuf[TICKREQLEN]; char authkey[DESKEYLEN]; Authenticator auth; int afd, i, v2; Ticketreq tr; Ticket t; AuthInfo *ai; if((afd = open("/mnt/factotum/ctl", ORDWR)) >= 0) return p9anyfactotum(fd, afd); if(readstr(fd, buf, sizeof buf) < 0) fatal(1, "cannot read p9any negotiation"); bbuf = buf; v2 = 0; if(strncmp(buf, "v.2 ", 4) == 0){ v2 = 1; bbuf += 4; } if((p = strchr(bbuf, ' '))) *p = 0; p = bbuf; if((dom = strchr(p, '@')) == nil) fatal(1, "bad p9any domain"); *dom++ = 0; if(strcmp(p, "p9sk1") != 0) fatal(1, "server did not offer p9sk1"); sprint(buf2, "%s %s", p, dom); if(write(fd, buf2, strlen(buf2)+1) != strlen(buf2)+1) fatal(1, "cannot write user/domain choice in p9any"); if(v2){ if(readstr(fd, buf, sizeof buf) != 3) fatal(1, "cannot read OK in p9any"); if(memcmp(buf, "OK\0", 3) != 0) fatal(1, "did not get OK in p9any"); } for(i=0; isecret = mallocz(8, 1); des56to64((uchar*)t.key, ai->secret); ai->nsecret = 8; ai->suid = strdup(t.suid); ai->cuid = strdup(t.cuid); memset(authkey, 0, sizeof authkey); return ai; } /* static int noauth(int fd) { ealgs = nil; return fd; } static int srvnoauth(int fd, char *user) { strecpy(user, user+MaxStr, getuser()); ealgs = nil; return fd; } */ void loghex(uchar *p, int n) { char buf[100]; int i; for(i = 0; i < n; i++) sprint(buf+2*i, "%2.2ux", p[i]); // syslog(0, "cpu", buf); } static int srvp9auth(int fd, char *user) { return -1; } /* * set authentication mechanism */ int setam(char *name) { for(am = authmethod; am->name != nil; am++) if(strcmp(am->name, name) == 0) return 0; am = authmethod; return -1; } /* * set authentication mechanism and encryption/hash algs * int setamalg(char *s) { ealgs = strchr(s, ' '); if(ealgs != nil) *ealgs++ = 0; return setam(s); } */ drawterm-20170818/cpu.c000066400000000000000000000336711314554504700145700ustar00rootroot00000000000000/* * cpu.c - Make a connection to a cpu server * * Invoked by listen as 'cpu -R | -N service net netdir' * by users as 'cpu [-h system] [-c cmd args ...]' */ #include #include #include #include #include #include #include "args.h" #include "drawterm.h" #define Maxfdata 8192 #define MaxStr 128 static void fatal(int, char*, ...); static void usage(void); static void writestr(int, char*, char*, int); static int readstr(int, char*, int); static char *rexcall(int*, char*, char*); static char *keyspec = ""; static AuthInfo *p9any(int); #define system csystem static char *system; static int cflag; extern int dbg; extern char* base; // fs base for devroot static char *srvname = "ncpu"; static char *ealgs = "rc4_256 sha1"; /* message size for exportfs; may be larger so we can do big graphics in CPU window */ static int msgsize = Maxfdata+IOHDRSZ; /* authentication mechanisms */ static int netkeyauth(int); static int netkeysrvauth(int, char*); static int p9auth(int); static int srvp9auth(int, char*); char *authserver; typedef struct AuthMethod AuthMethod; struct AuthMethod { char *name; /* name of method */ int (*cf)(int); /* client side authentication */ int (*sf)(int, char*); /* server side authentication */ } authmethod[] = { { "p9", p9auth, srvp9auth,}, { "netkey", netkeyauth, netkeysrvauth,}, // { "none", noauth, srvnoauth,}, { 0 } }; AuthMethod *am = authmethod; /* default is p9 */ char *p9authproto = "p9any"; int setam(char*); void exits(char *s) { print("\ngoodbye\n"); for(;;) osyield(); } void usage(void) { fprint(2, "usage: drawterm [-a authserver] [-c cpuserver] [-s secstore] [-u user]\n"); exits("usage"); } int fdd; int mountfactotum(void) { int fd; if((fd = dialfactotum()) < 0) return -1; if(sysmount(fd, -1, "/mnt/factotum", MREPL, "") < 0){ fprint(2, "mount factotum: %r\n"); return -1; } if((fd = open("/mnt/factotum/ctl", OREAD)) < 0){ fprint(2, "open /mnt/factotum/ctl: %r\n"); return -1; } close(fd); return 0; } void cpumain(int argc, char **argv) { char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *err, *secstoreserver, *p, *s; int fd, ms, data; /* see if we should use a larger message size */ fd = open("/dev/draw", OREAD); if(fd > 0){ ms = iounit(fd); if(msgsize < ms+IOHDRSZ) msgsize = ms+IOHDRSZ; close(fd); } user = getenv("USER"); secstoreserver = nil; authserver = getenv("auth"); if(authserver == nil) authserver = "auth"; system = getenv("cpu"); if(system == nil) system = "cpu"; ARGBEGIN{ case 'a': authserver = EARGF(usage()); break; case 'c': system = EARGF(usage()); break; case 'd': dbg++; break; case 'e': ealgs = EARGF(usage()); if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) ealgs = nil; break; case 'C': cflag++; cmd[0] = '!'; cmd[1] = '\0'; while((p = ARGF()) != nil) { strcat(cmd, " "); strcat(cmd, p); } break; case 'k': keyspec = EARGF(usage()); break; case 'r': base = EARGF(usage()); break; case 's': secstoreserver = EARGF(usage()); break; case 'u': user = EARGF(usage()); break; default: usage(); }ARGEND; if(argc != 0) usage(); if(user == nil) user = readcons("user", nil, 0); if(mountfactotum() < 0){ if(secstoreserver == nil) secstoreserver = authserver; if(havesecstore(secstoreserver, user)){ s = secstorefetch(secstoreserver, user, nil); if(s){ if(strlen(s) >= sizeof secstorebuf) sysfatal("secstore data too big"); strcpy(secstorebuf, s); } } } if((err = rexcall(&data, system, srvname))) fatal(1, "%s: %s", err, system); /* Tell the remote side the command to execute and where our working directory is */ if(cflag) writestr(data, cmd, "command", 0); if(getcwd(dat, sizeof(dat)) == 0) writestr(data, "NO", "dir", 0); else writestr(data, dat, "dir", 0); /* * Wait for the other end to execute and start our file service * of /mnt/term */ if(readstr(data, buf, sizeof(buf)) < 0) fatal(1, "waiting for FS: %r"); if(strncmp("FS", buf, 2) != 0) { print("remote cpu: %s", buf); exits(buf); } if(readstr(data, buf, sizeof buf) < 0) fatal(1, "waiting for remote export: %r"); if(strcmp(buf, "/") != 0){ print("remote cpu: %s" , buf); exits(buf); } write(data, "OK", 2); /* Begin serving the gnot namespace */ exportfs(data, msgsize); fatal(1, "starting exportfs"); } void fatal(int syserr, char *fmt, ...) { Fmt f; char *str; va_list arg; fmtstrinit(&f); fmtprint(&f, "cpu: "); va_start(arg, fmt); fmtvprint(&f, fmt, arg); va_end(arg); if(syserr) fmtprint(&f, ": %r"); fmtprint(&f, "\n"); str = fmtstrflush(&f); write(2, str, strlen(str)); exits(str); } char *negstr = "negotiating authentication method"; char bug[256]; char* rexcall(int *fd, char *host, char *service) { char *na; char dir[MaxStr]; char err[ERRMAX]; char msg[MaxStr]; int n; na = netmkaddr(host, "tcp", "17010"); if((*fd = dial(na, 0, dir, 0)) < 0) return "can't dial"; /* negotiate authentication mechanism */ if(ealgs != nil) snprint(msg, sizeof(msg), "%s %s", am->name, ealgs); else snprint(msg, sizeof(msg), "%s", am->name); writestr(*fd, msg, negstr, 0); n = readstr(*fd, err, sizeof err); if(n < 0) return negstr; if(*err){ werrstr(err); return negstr; } /* authenticate */ *fd = (*am->cf)(*fd); if(*fd < 0) return "can't authenticate"; return 0; } void writestr(int fd, char *str, char *thing, int ignore) { int l, n; l = strlen(str); n = write(fd, str, l+1); if(!ignore && n < 0) fatal(1, "writing network: %s", thing); } int readstr(int fd, char *str, int len) { int n; while(len) { n = read(fd, str, 1); if(n < 0) return -1; if(*str == '\0') return 0; str++; len--; } return -1; } static int readln(char *buf, int n) { int i; char *p; n--; /* room for \0 */ p = buf; for(i=0; isecret, ai->nsecret); if(ealgs == nil) return fd; /* exchange random numbers */ for(i = 0; i < 4; i++) key[i] = fastrand(); if(write(fd, key, 4) != 4) return -1; if(readn(fd, key+12, 4) != 4) return -1; /* scramble into two secrets */ sha1(key, sizeof(key), digest, nil); mksecret(fromclientsecret, digest); mksecret(fromserversecret, digest+10); /* set up encryption */ i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil); if(i < 0) werrstr("can't establish ssl connection: %r"); return i; } int authdial(char *net, char *dom) { int fd; fd = dial(netmkaddr(authserver, "tcp", "567"), 0, 0, 0); //print("authdial %d\n", fd); return fd; } static int getastickets(Ticketreq *tr, char *trbuf, char *tbuf) { int asfd, rv; char *dom; dom = tr->authdom; asfd = authdial(nil, dom); if(asfd < 0) return -1; rv = _asgetticket(asfd, trbuf, tbuf); close(asfd); return rv; } static int mkserverticket(Ticketreq *tr, char *authkey, char *tbuf) { int i; Ticket t; if(strcmp(tr->authid, tr->hostid) != 0) return -1; memset(&t, 0, sizeof(t)); memmove(t.chal, tr->chal, CHALLEN); strcpy(t.cuid, tr->uid); strcpy(t.suid, tr->uid); for(i=0; i= 0) return 0; return mkserverticket(tr, key, tbuf); } /* * prompt user for a key. don't care about memory leaks, runs standalone */ static Attr* promptforkey(char *params) { char *v; int fd; Attr *a, *attr; char *def; fd = open("/dev/cons", ORDWR); if(fd < 0) sysfatal("opening /dev/cons: %r"); attr = _parseattr(params); fprint(fd, "\n!Adding key:"); for(a=attr; a; a=a->next) if(a->type != AttrQuery && a->name[0] != '!') fprint(fd, " %q=%q", a->name, a->val); fprint(fd, "\n"); for(a=attr; a; a=a->next){ v = a->name; if(a->type != AttrQuery || v[0]=='!') continue; def = nil; if(strcmp(v, "user") == 0) def = getuser(); a->val = readcons(v, def, 0); if(a->val == nil) sysfatal("user terminated key input"); a->type = AttrNameval; } for(a=attr; a; a=a->next){ v = a->name; if(a->type != AttrQuery || v[0]!='!') continue; def = nil; if(strcmp(v+1, "user") == 0) def = getuser(); a->val = readcons(v+1, def, 1); if(a->val == nil) sysfatal("user terminated key input"); a->type = AttrNameval; } fprint(fd, "!\n"); close(fd); return attr; } /* * send a key to the mounted factotum */ static int sendkey(Attr *attr) { int fd, rv; char buf[1024]; fd = open("/mnt/factotum/ctl", ORDWR); if(fd < 0) sysfatal("opening /mnt/factotum/ctl: %r"); rv = fprint(fd, "key %A\n", attr); read(fd, buf, sizeof buf); close(fd); return rv; } int askuser(char *params) { Attr *attr; fmtinstall('A', _attrfmt); attr = promptforkey(params); if(attr == nil) sysfatal("no key supplied"); if(sendkey(attr) < 0) sysfatal("sending key to factotum: %r"); return 0; } AuthInfo* p9anyfactotum(int fd, int afd) { return auth_proxy(fd, askuser, "proto=p9any role=client %s", keyspec); } AuthInfo* p9any(int fd) { char buf[1024], buf2[1024], cchal[CHALLEN], *bbuf, *p, *dom, *u; char *pass; char tbuf[TICKETLEN+TICKETLEN+AUTHENTLEN], trbuf[TICKREQLEN]; char authkey[DESKEYLEN]; Authenticator auth; int afd, i, n, v2; Ticketreq tr; Ticket t; AuthInfo *ai; if((afd = open("/mnt/factotum/ctl", ORDWR)) >= 0) return p9anyfactotum(fd, afd); werrstr(""); if(readstr(fd, buf, sizeof buf) < 0) fatal(1, "cannot read p9any negotiation"); bbuf = buf; v2 = 0; if(strncmp(buf, "v.2 ", 4) == 0){ v2 = 1; bbuf += 4; } if((p = strchr(bbuf, ' '))) *p = 0; p = bbuf; if((dom = strchr(p, '@')) == nil) fatal(1, "bad p9any domain"); *dom++ = 0; if(strcmp(p, "p9sk1") != 0) fatal(1, "server did not offer p9sk1"); sprint(buf2, "%s %s", p, dom); if(write(fd, buf2, strlen(buf2)+1) != strlen(buf2)+1) fatal(1, "cannot write user/domain choice in p9any"); if(v2){ if((n = readstr(fd, buf, sizeof buf)) < 0) fatal(1, "cannot read OK in p9any: got %d %s", n, buf); if(memcmp(buf, "OK\0", 3) != 0) fatal(1, "did not get OK in p9any"); } for(i=0; i 0) n += i; buf[n] = 0; werrstr(""); fatal(0, "server says: %s", buf); } convM2A(tbuf, &auth, t.key); if(auth.num != AuthAs || memcmp(auth.chal, cchal, CHALLEN) != 0 || auth.id != 0){ print("?you and auth server agree about password.\n"); print("?server is confused.\n"); fatal(0, "server lies got %llux.%d want %llux.%d", *(vlong*)auth.chal, auth.id, *(vlong*)cchal, 0); } //print("i am %s there.\n", t.suid); ai = mallocz(sizeof(AuthInfo), 1); ai->secret = mallocz(8, 1); des56to64((uchar*)t.key, ai->secret); ai->nsecret = 8; ai->suid = strdup(t.suid); ai->cuid = strdup(t.cuid); memset(authkey, 0, sizeof authkey); return ai; } /* static int noauth(int fd) { ealgs = nil; return fd; } static int srvnoauth(int fd, char *user) { strecpy(user, user+MaxStr, getuser()); ealgs = nil; return fd; } */ void loghex(uchar *p, int n) { char buf[100]; int i; for(i = 0; i < n; i++) sprint(buf+2*i, "%2.2ux", p[i]); // syslog(0, "cpu", buf); } static int srvp9auth(int fd, char *user) { return -1; } /* * set authentication mechanism */ int setam(char *name) { for(am = authmethod; am->name != nil; am++) if(strcmp(am->name, name) == 0) return 0; am = authmethod; return -1; } /* * set authentication mechanism and encryption/hash algs * int setamalg(char *s) { ealgs = strchr(s, ' '); if(ealgs != nil) *ealgs++ = 0; return setam(s); } */ drawterm-20170818/drawterm.h000066400000000000000000000007301314554504700156210ustar00rootroot00000000000000extern int havesecstore(char *addr, char *owner); extern char *secstore; extern char secstorebuf[65536]; extern char *secstorefetch(char *addr, char *owner, char *passwd); extern char *authserver; extern char *readcons(char *prompt, char *def, int secret); extern int exportfs(int, int); extern char *user; extern char *getkey(char*, char*); extern char *findkey(char**, char*); extern int dialfactotum(void); extern char *getuser(void); extern void cpumain(int, char**); drawterm-20170818/drawterm.ico000066400000000000000000000031761314554504700161530ustar00rootroot0000000000000000h(0`"""333DDDUUUfffwwwܺU˗uUDfTiݹuTVVtV|˨SFX̨JʇeCGݸjۋZ݆ffhi[wˈuJXܦ[YYYiGweۆݦhܖۇzݦݸXݦWܷwݶ݆xݖݕ}܇dLۈًwHيۼȜݹDݷ۷|ݗۻݗ{ܘݘݬݘ܊(ݙzݙ݈݉܊gڊxȜNjiܘݘʉۛQ)˙ɽ"}˘A&ͩʙʵ$ۛ2ݻj͸wʽډr|jڛ˨Uݺۊxw˻ۗxɊݘܫdrawterm-20170818/drawterm.rc000066400000000000000000000032611314554504700160000ustar00rootroot00000000000000//Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ICON1 ICON DISCARDABLE "drawterm.ico" #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED drawterm-20170818/drawterm.res000066400000000000000000000033341314554504700161660ustar00rootroot00000000000000 h 0 (0`"""333DDDUUUfffwwwܺU˗uUDfTiݹuTVVtV|˨SFX̨JʇeCGݸjۋZ݆ffhi[wˈuJXܦ[YYYiGweۆݦhܖۇzݦݸXݦWܷwݶ݆xݖݕ}܇dLۈًwHيۼȜݹDݷ۷|ݗۻݗ{ܘݘݬݘ܊(ݙzݙ݈݉܊gڊxȜNjiܘݘʉۛQ)˙ɽ"}˘A&ͩʙʵ$ۛ2ݻj͸wʽډr|jڛ˨Uݺۊxw˻ۗxɊݘܫ e0 00hdrawterm-20170818/exportfs/000077500000000000000000000000001314554504700154755ustar00rootroot00000000000000drawterm-20170818/exportfs/Makefile000066400000000000000000000003101314554504700171270ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libexportfs.a OFILES=\ exportfs.$O\ exportsrv.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/exportfs/exportfs.c000066400000000000000000000203361314554504700175170ustar00rootroot00000000000000/* * exportfs - Export a plan 9 name space across a network */ #include #include #include #include #include "drawterm.h" #define Extern #include "exportfs.h" /* #define QIDPATH ((1LL<<48)-1) */ #define QIDPATH ((((vlong)1)<<48)-1) vlong newqid = 0; void (*fcalls[256])(Fsrpc*); /* accounting and debugging counters */ int filecnt; int freecnt; int qidcnt; int qfreecnt; int ncollision; int netfd; int exportfs(int fd, int msgsz) { char buf[ERRMAX], ebuf[ERRMAX]; Fsrpc *r; int i, n; fcalls[Tversion] = Xversion; fcalls[Tauth] = Xauth; fcalls[Tflush] = Xflush; fcalls[Tattach] = Xattach; fcalls[Twalk] = Xwalk; fcalls[Topen] = slave; fcalls[Tcreate] = Xcreate; fcalls[Tclunk] = Xclunk; fcalls[Tread] = slave; fcalls[Twrite] = slave; fcalls[Tremove] = Xremove; fcalls[Tstat] = Xstat; fcalls[Twstat] = Xwstat; srvfd = -1; netfd = fd; //dbg = 1; strcpy(buf, "this is buf"); strcpy(ebuf, "this is ebuf"); DEBUG(DFD, "exportfs: started\n"); // rfork(RFNOTEG); messagesize = msgsz; if(messagesize == 0){ messagesize = iounit(netfd); if(messagesize == 0) messagesize = 8*8192+IOHDRSZ; } Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs); // for(i=0; ibuf, messagesize); if(n <= 0) fatal("eof: n=%d %r", n); if(convM2S(r->buf, n, &r->work) == 0){ iprint("convM2S %d byte message\n", n); for(i=0; ibuf[i]); if(i%16 == 15) iprint("\n"); } if(i%16) iprint("\n"); fatal("convM2S format error"); } if(0) iprint("<- %F\n", &r->work); DEBUG(DFD, "%F\n", &r->work); (fcalls[r->work.type])(r); } } void reply(Fcall *r, Fcall *t, char *err) { uchar *data; int m, n; t->tag = r->tag; t->fid = r->fid; if(err) { t->type = Rerror; t->ename = err; } else t->type = r->type + 1; if(0) iprint("-> %F\n", t); DEBUG(DFD, "\t%F\n", t); data = malloc(messagesize); /* not mallocz; no need to clear */ if(data == nil) fatal(Enomem); n = convS2M(t, data, messagesize); if((m=write(netfd, data, n))!=n){ iprint("wrote %d got %d (%r)\n", n, m); fatal("write"); } free(data); } Fid * getfid(int nr) { Fid *f; for(f = fidhash(nr); f; f = f->next) if(f->nr == nr) return f; return 0; } int freefid(int nr) { Fid *f, **l; char buf[128]; l = &fidhash(nr); for(f = *l; f; f = f->next) { if(f->nr == nr) { if(f->mid) { sprint(buf, "/mnt/exportfs/%d", f->mid); unmount(0, buf); psmap[f->mid] = 0; } if(f->f) { freefile(f->f); f->f = nil; } *l = f->next; f->next = fidfree; fidfree = f; return 1; } l = &f->next; } return 0; } Fid * newfid(int nr) { Fid *new, **l; int i; l = &fidhash(nr); for(new = *l; new; new = new->next) if(new->nr == nr) return 0; if(fidfree == 0) { fidfree = emallocz(sizeof(Fid) * Fidchunk); for(i = 0; i < Fidchunk-1; i++) fidfree[i].next = &fidfree[i+1]; fidfree[Fidchunk-1].next = 0; } new = fidfree; fidfree = new->next; memset(new, 0, sizeof(Fid)); new->next = *l; *l = new; new->nr = nr; new->fid = -1; new->mid = 0; return new; } Fsrpc * getsbuf(void) { static int ap; int look, rounds; Fsrpc *wb; int small_instead_of_fast = 1; if(small_instead_of_fast) ap = 0; /* so we always start looking at the beginning and reuse buffers */ for(rounds = 0; rounds < 10; rounds++) { for(look = 0; look < Nr_workbufs; look++) { if(++ap == Nr_workbufs) ap = 0; if(Workq[ap].busy == 0) break; } if(look == Nr_workbufs){ sleep(10 * rounds); continue; } wb = &Workq[ap]; wb->pid = 0; wb->canint = 0; wb->flushtag = NOTAG; wb->busy = 1; if(wb->buf == nil) /* allocate buffers dynamically to keep size down */ wb->buf = emallocz(messagesize); return wb; } fatal("No more work buffers"); return nil; } void freefile(File *f) { File *parent, *child; Loop: f->ref--; if(f->ref > 0) return; freecnt++; if(f->ref < 0) abort(); DEBUG(DFD, "free %s\n", f->name); /* delete from parent */ parent = f->parent; if(parent->child == f) parent->child = f->childlist; else{ for(child=parent->child; child->childlist!=f; child=child->childlist) if(child->childlist == nil) fatal("bad child list"); child->childlist = f->childlist; } freeqid(f->qidt); free(f->name); f->name = nil; free(f); f = parent; if(f != nil) goto Loop; } File * file(File *parent, char *name) { Dir *dir; char *path; File *f; DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name); path = makepath(parent, name); dir = dirstat(path); free(path); if(dir == nil) return nil; for(f = parent->child; f; f = f->childlist) if(strcmp(name, f->name) == 0) break; if(f == nil){ f = emallocz(sizeof(File)); f->name = estrdup(name); f->parent = parent; f->childlist = parent->child; parent->child = f; parent->ref++; f->ref = 0; filecnt++; } f->ref++; f->qid.type = dir->qid.type; f->qid.vers = dir->qid.vers; f->qidt = uniqueqid(dir); f->qid.path = f->qidt->uniqpath; f->inval = 0; free(dir); return f; } void initroot(void) { Dir *dir; root = emallocz(sizeof(File)); root->name = estrdup("."); dir = dirstat(root->name); if(dir == nil) fatal("root stat"); root->ref = 1; root->qid.vers = dir->qid.vers; root->qidt = uniqueqid(dir); root->qid.path = root->qidt->uniqpath; root->qid.type = QTDIR; free(dir); psmpt = emallocz(sizeof(File)); psmpt->name = estrdup("/"); dir = dirstat(psmpt->name); if(dir == nil) return; psmpt->ref = 1; psmpt->qid.vers = dir->qid.vers; psmpt->qidt = uniqueqid(dir); psmpt->qid.path = psmpt->qidt->uniqpath; free(dir); psmpt = file(psmpt, "mnt"); if(psmpt == 0) return; psmpt = file(psmpt, "exportfs"); } char* makepath(File *p, char *name) { int i, n; char *c, *s, *path, *seg[256]; seg[0] = name; n = strlen(name)+2; for(i = 1; i < 256 && p; i++, p = p->parent){ seg[i] = p->name; n += strlen(p->name)+1; } path = malloc(n); if(path == nil) fatal("out of memory"); s = path; while(i--) { for(c = seg[i]; *c; c++) *s++ = *c; *s++ = '/'; } while(s[-1] == '/') s--; *s = '\0'; return path; } int qidhash(vlong path) { int h, n; h = 0; for(n=0; n<64; n+=Nqidbits){ h ^= path; path >>= Nqidbits; } return h & (Nqidtab-1); } void freeqid(Qidtab *q) { ulong h; Qidtab *l; q->ref--; if(q->ref > 0) return; qfreecnt++; h = qidhash(q->path); if(qidtab[h] == q) qidtab[h] = q->next; else{ for(l=qidtab[h]; l->next!=q; l=l->next) if(l->next == nil) fatal("bad qid list"); l->next = q->next; } free(q); } Qidtab* qidlookup(Dir *d) { ulong h; Qidtab *q; h = qidhash(d->qid.path); for(q=qidtab[h]; q!=nil; q=q->next) if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path) return q; return nil; } int qidexists(vlong path) { int h; Qidtab *q; for(h=0; hnext) if(q->uniqpath == path) return 1; return 0; } Qidtab* uniqueqid(Dir *d) { ulong h; vlong path; Qidtab *q; q = qidlookup(d); if(q != nil){ q->ref++; return q; } path = d->qid.path; while(qidexists(path)){ DEBUG(DFD, "collision on %s\n", d->name); /* collision: find a new one */ ncollision++; path &= QIDPATH; ++newqid; if(newqid >= (1<<16)){ DEBUG(DFD, "collision wraparound\n"); newqid = 1; } path |= newqid<<48; DEBUG(DFD, "assign qid %.16llux\n", path); } q = mallocz(sizeof(Qidtab), 1); if(q == nil) fatal("no memory for qid table"); qidcnt++; q->ref = 1; q->type = d->type; q->dev = d->dev; q->path = d->qid.path; q->uniqpath = path; h = qidhash(d->qid.path); q->next = qidtab[h]; qidtab[h] = q; return q; } void fatal(char *s, ...) { char buf[ERRMAX]; va_list arg; if (s) { va_start(arg, s); vsnprint(buf, ERRMAX, s, arg); va_end(arg); } /* Clear away the slave children */ // for(m = Proclist; m; m = m->next) // postnote(PNPROC, m->pid, "kill"); DEBUG(DFD, "%s\n", buf); if (s) sysfatal(buf); else sysfatal(""); } drawterm-20170818/exportfs/exportfs.h000066400000000000000000000052621314554504700175250ustar00rootroot00000000000000/* * exportfs.h - definitions for exporting file server */ #define DEBUG if(!dbg){}else fprint #define DFD 2 #define fidhash(s) fhash[s%FHASHSIZE] #define Proc Exproc typedef struct Fsrpc Fsrpc; typedef struct Fid Fid; typedef struct File File; typedef struct Proc Proc; typedef struct Qidtab Qidtab; struct Fsrpc { int busy; /* Work buffer has pending rpc to service */ int pid; /* Pid of slave process executing the rpc */ int canint; /* Interrupt gate */ int flushtag; /* Tag on which to reply to flush */ Fcall work; /* Plan 9 incoming Fcall */ uchar *buf; /* Data buffer */ }; struct Fid { int fid; /* system fd for i/o */ File *f; /* File attached to this fid */ int mode; int nr; /* fid number */ int mid; /* Mount id */ Fid *next; /* hash link */ }; struct File { char *name; int ref; Qid qid; Qidtab *qidt; int inval; File *parent; File *child; File *childlist; }; struct Proc { int pid; int busy; Proc *next; }; struct Qidtab { int ref; int type; int dev; vlong path; vlong uniqpath; Qidtab *next; }; enum { MAXPROC = 50, FHASHSIZE = 64, Nr_workbufs = 50, Fidchunk = 1000, Npsmpt = 32, Nqidbits = 5, Nqidtab = (1< #include #include #define Extern extern #include "exportfs.h" char Ebadfid[] = "Bad fid"; char Enotdir[] = "Not a directory"; char Edupfid[] = "Fid already in use"; char Eopen[] = "Fid already opened"; char Exmnt[] = "Cannot .. past mount point"; char Emip[] = "Mount in progress"; char Enopsmt[] = "Out of pseudo mount points"; char Enomem[] = "No memory"; char Eversion[] = "Bad 9P2000 version"; int iounit(int x) { return 8*8192+IOHDRSZ; } void* emallocz(ulong n) { void *v; v = mallocz(n, 1); if(v == nil) panic("out of memory"); return v; } void Xversion(Fsrpc *t) { Fcall rhdr; if(t->work.msize > messagesize) t->work.msize = messagesize; messagesize = t->work.msize; if(strncmp(t->work.version, "9P2000", 6) != 0){ reply(&t->work, &rhdr, Eversion); return; } rhdr.version = "9P2000"; rhdr.msize = t->work.msize; reply(&t->work, &rhdr, 0); t->busy = 0; } void Xauth(Fsrpc *t) { Fcall rhdr; reply(&t->work, &rhdr, "exportfs: authentication not required"); t->busy = 0; } void Xflush(Fsrpc *t) { Fsrpc *w, *e; Fcall rhdr; e = &Workq[Nr_workbufs]; for(w = Workq; w < e; w++) { if(w->work.tag == t->work.oldtag) { DEBUG(DFD, "\tQ busy %d pid %d can %d\n", w->busy, w->pid, w->canint); if(w->busy && w->pid) { w->flushtag = t->work.tag; DEBUG(DFD, "\tset flushtag %d\n", t->work.tag); // if(w->canint) // postnote(PNPROC, w->pid, "flush"); t->busy = 0; return; } } } reply(&t->work, &rhdr, 0); DEBUG(DFD, "\tflush reply\n"); t->busy = 0; } void Xattach(Fsrpc *t) { Fcall rhdr; Fid *f; f = newfid(t->work.fid); if(f == 0) { reply(&t->work, &rhdr, Ebadfid); t->busy = 0; return; } if(srvfd >= 0){ /* if(psmpt == 0){ Nomount: reply(&t->work, &rhdr, Enopsmt); t->busy = 0; freefid(t->work.fid); return; } for(i=0; i= Npsmpt) goto Nomount; sprint(buf, "%d", i); f->f = file(psmpt, buf); if(f->f == nil) goto Nomount; sprint(buf, "/mnt/exportfs/%d", i); nfd = dup(srvfd, -1); if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){ errstr(buf, sizeof buf); reply(&t->work, &rhdr, buf); t->busy = 0; freefid(t->work.fid); close(nfd); return; } psmap[i] = 1; f->mid = i; */ }else{ f->f = root; f->f->ref++; } rhdr.qid = f->f->qid; reply(&t->work, &rhdr, 0); t->busy = 0; } Fid* clonefid(Fid *f, int new) { Fid *n; n = newfid(new); if(n == 0) { n = getfid(new); if(n == 0) fatal("inconsistent fids"); if(n->fid >= 0) close(n->fid); freefid(new); n = newfid(new); if(n == 0) fatal("inconsistent fids2"); } n->f = f->f; n->f->ref++; return n; } void Xwalk(Fsrpc *t) { char err[ERRMAX], *e; Fcall rhdr; Fid *f, *nf; File *wf; int i; f = getfid(t->work.fid); if(f == 0) { reply(&t->work, &rhdr, Ebadfid); t->busy = 0; return; } nf = nil; if(t->work.newfid != t->work.fid){ nf = clonefid(f, t->work.newfid); f = nf; } rhdr.nwqid = 0; e = nil; for(i=0; iwork.nwname; i++){ if(i == MAXWELEM){ e = "Too many path elements"; break; } if(strcmp(t->work.wname[i], "..") == 0) { if(f->f->parent == nil) { e = Exmnt; break; } wf = f->f->parent; wf->ref++; goto Accept; } wf = file(f->f, t->work.wname[i]); if(wf == 0){ errstr(err, sizeof err); e = err; break; } Accept: freefile(f->f); rhdr.wqid[rhdr.nwqid++] = wf->qid; f->f = wf; continue; } if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname)) freefid(t->work.newfid); if(rhdr.nwqid > 0) e = nil; reply(&t->work, &rhdr, e); t->busy = 0; } void Xclunk(Fsrpc *t) { Fcall rhdr; Fid *f; f = getfid(t->work.fid); if(f == 0) { reply(&t->work, &rhdr, Ebadfid); t->busy = 0; return; } if(f->fid >= 0) close(f->fid); freefid(t->work.fid); reply(&t->work, &rhdr, 0); t->busy = 0; } void Xstat(Fsrpc *t) { char err[ERRMAX], *path; Fcall rhdr; Fid *f; Dir *d; int s; uchar *statbuf; f = getfid(t->work.fid); if(f == 0) { reply(&t->work, &rhdr, Ebadfid); t->busy = 0; return; } if(f->fid >= 0) d = dirfstat(f->fid); else { path = makepath(f->f, ""); d = dirstat(path); free(path); } if(d == nil) { errstr(err, sizeof err); reply(&t->work, &rhdr, err); t->busy = 0; return; } d->qid.path = f->f->qidt->uniqpath; s = sizeD2M(d); statbuf = emallocz(s); s = convD2M(d, statbuf, s); free(d); rhdr.nstat = s; rhdr.stat = statbuf; reply(&t->work, &rhdr, 0); free(statbuf); t->busy = 0; } static int getiounit(int fd) { int n; n = iounit(fd); if(n > messagesize-IOHDRSZ) n = messagesize-IOHDRSZ; return n; } void Xcreate(Fsrpc *t) { char err[ERRMAX], *path; Fcall rhdr; Fid *f; File *nf; f = getfid(t->work.fid); if(f == 0) { reply(&t->work, &rhdr, Ebadfid); t->busy = 0; return; } path = makepath(f->f, t->work.name); f->fid = create(path, t->work.mode, t->work.perm); free(path); if(f->fid < 0) { errstr(err, sizeof err); reply(&t->work, &rhdr, err); t->busy = 0; return; } nf = file(f->f, t->work.name); if(nf == 0) { errstr(err, sizeof err); reply(&t->work, &rhdr, err); t->busy = 0; return; } f->mode = t->work.mode; freefile(f->f); f->f = nf; rhdr.qid = f->f->qid; rhdr.iounit = getiounit(f->fid); reply(&t->work, &rhdr, 0); t->busy = 0; } void Xremove(Fsrpc *t) { char err[ERRMAX], *path; Fcall rhdr; Fid *f; f = getfid(t->work.fid); if(f == 0) { reply(&t->work, &rhdr, Ebadfid); t->busy = 0; return; } path = makepath(f->f, ""); DEBUG(DFD, "\tremove: %s\n", path); if(remove(path) < 0) { free(path); errstr(err, sizeof err); reply(&t->work, &rhdr, err); t->busy = 0; return; } free(path); f->f->inval = 1; if(f->fid >= 0) close(f->fid); freefid(t->work.fid); reply(&t->work, &rhdr, 0); t->busy = 0; } void Xwstat(Fsrpc *t) { char err[ERRMAX], *path; Fcall rhdr; Fid *f; int s; char *strings; Dir d; f = getfid(t->work.fid); if(f == 0) { reply(&t->work, &rhdr, Ebadfid); t->busy = 0; return; } strings = emallocz(t->work.nstat); /* ample */ if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){ rerrstr(err, sizeof err); reply(&t->work, &rhdr, err); t->busy = 0; free(strings); return; } if(f->fid >= 0) s = dirfwstat(f->fid, &d); else { path = makepath(f->f, ""); s = dirwstat(path, &d); free(path); } if(s < 0) { rerrstr(err, sizeof err); reply(&t->work, &rhdr, err); } else { /* wstat may really be rename */ if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){ free(f->f->name); f->f->name = estrdup(d.name); } reply(&t->work, &rhdr, 0); } free(strings); t->busy = 0; } void slave(Fsrpc *f) { Proc *p; int pid; static int nproc; for(;;) { for(p = Proclist; p; p = p->next) { if(p->busy == 0) { f->pid = p->pid; p->busy = 1; pid = (uintptr)rendezvous((void*)(uintptr)p->pid, f); if(pid != p->pid) fatal("rendezvous sync fail"); return; } } if(++nproc > MAXPROC) fatal("too many procs"); pid = kproc("slave", blockingslave, nil); DEBUG(DFD, "slave pid %d\n", pid); if(pid == -1) fatal("kproc"); p = malloc(sizeof(Proc)); if(p == 0) fatal("out of memory"); p->busy = 0; p->pid = pid; p->next = Proclist; Proclist = p; DEBUG(DFD, "parent %d rendez\n", pid); rendezvous((void*)(uintptr)pid, p); DEBUG(DFD, "parent %d went\n", pid); } } void blockingslave(void *x) { Fsrpc *p; Fcall rhdr; Proc *m; int pid; USED(x); notify(flushaction); pid = getpid(); DEBUG(DFD, "blockingslave %d rendez\n", pid); m = (Proc*)rendezvous((void*)(uintptr)pid, 0); DEBUG(DFD, "blockingslave %d rendez got %p\n", pid, m); for(;;) { p = rendezvous((void*)(uintptr)pid, (void*)(uintptr)pid); if((uintptr)p == ~(uintptr)0) /* Interrupted */ continue; DEBUG(DFD, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid); if(p->flushtag != NOTAG) goto flushme; switch(p->work.type) { case Tread: slaveread(p); break; case Twrite: slavewrite(p); break; case Topen: slaveopen(p); break; default: reply(&p->work, &rhdr, "exportfs: slave type error"); } if(p->flushtag != NOTAG) { flushme: p->work.type = Tflush; p->work.tag = p->flushtag; reply(&p->work, &rhdr, 0); } p->busy = 0; m->busy = 0; } } int openmount(int sfd) { werrstr("openmount not implemented"); return -1; } void slaveopen(Fsrpc *p) { char err[ERRMAX], *path; Fcall *work, rhdr; Fid *f; Dir *d; work = &p->work; f = getfid(work->fid); if(f == 0) { reply(work, &rhdr, Ebadfid); return; } if(f->fid >= 0) { close(f->fid); f->fid = -1; } path = makepath(f->f, ""); DEBUG(DFD, "\topen: %s %d\n", path, work->mode); p->canint = 1; if(p->flushtag != NOTAG){ free(path); return; } /* There is a race here I ignore because there are no locks */ f->fid = open(path, work->mode); free(path); p->canint = 0; if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) { Error: errstr(err, sizeof err); reply(work, &rhdr, err); return; } f->f->qid = d->qid; free(d); if(f->f->qid.type & QTMOUNT){ /* fork new exportfs for this */ f->fid = openmount(f->fid); if(f->fid < 0) goto Error; } DEBUG(DFD, "\topen: fd %d\n", f->fid); f->mode = work->mode; rhdr.iounit = getiounit(f->fid); rhdr.qid = f->f->qid; reply(work, &rhdr, 0); } void slaveread(Fsrpc *p) { Fid *f; int n, r; Fcall *work, rhdr; char *data, err[ERRMAX]; work = &p->work; f = getfid(work->fid); if(f == 0) { reply(work, &rhdr, Ebadfid); return; } n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count; p->canint = 1; if(p->flushtag != NOTAG) return; data = malloc(n); if(data == nil) fatal(Enomem); /* can't just call pread, since directories must update the offset */ r = pread(f->fid, data, n, work->offset); p->canint = 0; if(r < 0) { free(data); errstr(err, sizeof err); reply(work, &rhdr, err); return; } DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r); rhdr.data = data; rhdr.count = r; reply(work, &rhdr, 0); free(data); } void slavewrite(Fsrpc *p) { char err[ERRMAX]; Fcall *work, rhdr; Fid *f; int n; work = &p->work; f = getfid(work->fid); if(f == 0) { reply(work, &rhdr, Ebadfid); return; } n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count; p->canint = 1; if(p->flushtag != NOTAG) return; n = pwrite(f->fid, work->data, n, work->offset); p->canint = 0; if(n < 0) { errstr(err, sizeof err); reply(work, &rhdr, err); return; } DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid); rhdr.count = n; reply(work, &rhdr, 0); } void reopen(Fid *f) { USED(f); fatal("reopen"); } void flushaction(void *a, char *cause) { USED(a); if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) { fprint(2, "exportsrv: note: %s\n", cause); exits("noted"); } if(strncmp(cause, "kill", 4) == 0) noted(NDFLT); noted(NCONT); } drawterm-20170818/gui-osx/000077500000000000000000000000001314554504700152165ustar00rootroot00000000000000drawterm-20170818/gui-osx/Makefile000066400000000000000000000003341314554504700166560ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libgui.a OFILES=\ alloc.$O\ cload.$O\ draw.$O\ load.$O\ screen.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/gui-osx/alloc.c000066400000000000000000000004361314554504700164570ustar00rootroot00000000000000#include #include #include #include Memimage* allocmemimage(Rectangle r, ulong chan) { return _allocmemimage(r, chan); } void freememimage(Memimage *i) { _freememimage(i); } void memfillcolor(Memimage *i, ulong val) { _memfillcolor(i, val); } drawterm-20170818/gui-osx/cload.c000066400000000000000000000002741314554504700164470ustar00rootroot00000000000000#include #include #include #include int cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) { return _cloadmemimage(i, r, data, ndata); } drawterm-20170818/gui-osx/draw.c000066400000000000000000000005551314554504700163240ustar00rootroot00000000000000#include #include #include #include void memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op) { _memimagedraw(_memimagedrawsetup(dst, r, src, sp, mask, mp, op)); } ulong pixelbits(Memimage *m, Point p) { return _pixelbits(m, p); } void memimageinit(void) { _memimageinit(); } drawterm-20170818/gui-osx/keycodes.h000066400000000000000000000111301314554504700171710ustar00rootroot00000000000000/* These are the Macintosh key scancode constants -- from Inside Macintosh */ #define QZ_ESCAPE 0x35 #define QZ_F1 0x7A #define QZ_F2 0x78 #define QZ_F3 0x63 #define QZ_F4 0x76 #define QZ_F5 0x60 #define QZ_F6 0x61 #define QZ_F7 0x62 #define QZ_F8 0x64 #define QZ_F9 0x65 #define QZ_F10 0x6D #define QZ_F11 0x67 #define QZ_F12 0x6F #define QZ_PRINT 0x69 #define QZ_SCROLLOCK 0x6B #define QZ_PAUSE 0x71 #define QZ_POWER 0x7F #define QZ_BACKQUOTE 0x32 #define QZ_1 0x12 #define QZ_2 0x13 #define QZ_3 0x14 #define QZ_4 0x15 #define QZ_5 0x17 #define QZ_6 0x16 #define QZ_7 0x1A #define QZ_8 0x1C #define QZ_9 0x19 #define QZ_0 0x1D #define QZ_MINUS 0x1B #define QZ_EQUALS 0x18 #define QZ_BACKSPACE 0x33 #define QZ_INSERT 0x72 #define QZ_HOME 0x73 #define QZ_PAGEUP 0x74 #define QZ_NUMLOCK 0x47 #define QZ_KP_EQUALS 0x51 #define QZ_KP_DIVIDE 0x4B #define QZ_KP_MULTIPLY 0x43 #define QZ_TAB 0x30 #define QZ_q 0x0C #define QZ_w 0x0D #define QZ_e 0x0E #define QZ_r 0x0F #define QZ_t 0x11 #define QZ_y 0x10 #define QZ_u 0x20 #define QZ_i 0x22 #define QZ_o 0x1F #define QZ_p 0x23 #define QZ_LEFTBRACKET 0x21 #define QZ_RIGHTBRACKET 0x1E #define QZ_BACKSLASH 0x2A #define QZ_DELETE 0x75 #define QZ_END 0x77 #define QZ_PAGEDOWN 0x79 #define QZ_KP7 0x59 #define QZ_KP8 0x5B #define QZ_KP9 0x5C #define QZ_KP_MINUS 0x4E #define QZ_CAPSLOCK 0x39 #define QZ_a 0x00 #define QZ_s 0x01 #define QZ_d 0x02 #define QZ_f 0x03 #define QZ_g 0x05 #define QZ_h 0x04 #define QZ_j 0x26 #define QZ_k 0x28 #define QZ_l 0x25 #define QZ_SEMICOLON 0x29 #define QZ_QUOTE 0x27 #define QZ_RETURN 0x24 #define QZ_KP4 0x56 #define QZ_KP5 0x57 #define QZ_KP6 0x58 #define QZ_KP_PLUS 0x45 #define QZ_LSHIFT 0x38 #define QZ_z 0x06 #define QZ_x 0x07 #define QZ_c 0x08 #define QZ_v 0x09 #define QZ_b 0x0B #define QZ_n 0x2D #define QZ_m 0x2E #define QZ_COMMA 0x2B #define QZ_PERIOD 0x2F #define QZ_SLASH 0x2C /* These are the same as the left versions - use left by default */ #if 0 #define QZ_RSHIFT 0x38 #endif #define QZ_UP 0x7E #define QZ_KP1 0x53 #define QZ_KP2 0x54 #define QZ_KP3 0x55 #define QZ_KP_ENTER 0x4C #define QZ_LCTRL 0x3B #define QZ_LALT 0x3A #define QZ_LMETA 0x37 #define QZ_SPACE 0x31 /* These are the same as the left versions - use left by default */ #if 0 #define QZ_RMETA 0x37 #define QZ_RALT 0x3A #define QZ_RCTRL 0x3B #endif #define QZ_LEFT 0x7B #define QZ_DOWN 0x7D #define QZ_RIGHT 0x7C #define QZ_KP0 0x52 #define QZ_KP_PERIOD 0x41 /* Wierd, these keys are on my iBook under MacOS X */ #define QZ_IBOOK_ENTER 0x34 #define QZ_IBOOK_LEFT 0x3B #define QZ_IBOOK_RIGHT 0x3C #define QZ_IBOOK_DOWN 0x3D #define QZ_IBOOK_UP 0x3E #define KEY_ENTER 13 #define KEY_TAB 9 #define KEY_BASE 0x100 /* Function keys */ #define KEY_F (KEY_BASE+64) /* Control keys */ #define KEY_CTRL (KEY_BASE) #define KEY_BACKSPACE (KEY_CTRL+0) #define KEY_DELETE (KEY_CTRL+1) #define KEY_INSERT (KEY_CTRL+2) #define KEY_HOME (KEY_CTRL+3) #define KEY_END (KEY_CTRL+4) #define KEY_PAGE_UP (KEY_CTRL+5) #define KEY_PAGE_DOWN (KEY_CTRL+6) #define KEY_ESC (KEY_CTRL+7) /* Control keys short name */ #define KEY_BS KEY_BACKSPACE #define KEY_DEL KEY_DELETE #define KEY_INS KEY_INSERT #define KEY_PGUP KEY_PAGE_UP #define KEY_PGDOWN KEY_PAGE_DOWN #define KEY_PGDWN KEY_PAGE_DOWN /* Cursor movement */ #define KEY_CRSR (KEY_BASE+16) #define KEY_RIGHT (KEY_CRSR+0) #define KEY_LEFT (KEY_CRSR+1) #define KEY_DOWN (KEY_CRSR+2) #define KEY_UP (KEY_CRSR+3) /* Multimedia keyboard/remote keys */ #define KEY_MM_BASE (0x100+384) #define KEY_POWER (KEY_MM_BASE+0) #define KEY_MENU (KEY_MM_BASE+1) #define KEY_PLAY (KEY_MM_BASE+2) #define KEY_PAUSE (KEY_MM_BASE+3) #define KEY_PLAYPAUSE (KEY_MM_BASE+4) #define KEY_STOP (KEY_MM_BASE+5) #define KEY_FORWARD (KEY_MM_BASE+6) #define KEY_REWIND (KEY_MM_BASE+7) #define KEY_NEXT (KEY_MM_BASE+8) #define KEY_PREV (KEY_MM_BASE+9) #define KEY_VOLUME_UP (KEY_MM_BASE+10) #define KEY_VOLUME_DOWN (KEY_MM_BASE+11) #define KEY_MUTE (KEY_MM_BASE+12) /* Keypad keys */ #define KEY_KEYPAD (KEY_BASE+32) #define KEY_KP0 (KEY_KEYPAD+0) #define KEY_KP1 (KEY_KEYPAD+1) #define KEY_KP2 (KEY_KEYPAD+2) #define KEY_KP3 (KEY_KEYPAD+3) #define KEY_KP4 (KEY_KEYPAD+4) #define KEY_KP5 (KEY_KEYPAD+5) #define KEY_KP6 (KEY_KEYPAD+6) #define KEY_KP7 (KEY_KEYPAD+7) #define KEY_KP8 (KEY_KEYPAD+8) #define KEY_KP9 (KEY_KEYPAD+9) #define KEY_KPDEC (KEY_KEYPAD+10) #define KEY_KPINS (KEY_KEYPAD+11) #define KEY_KPDEL (KEY_KEYPAD+12) #define KEY_KPENTER (KEY_KEYPAD+13) /* Special keys */ #define KEY_INTERN (0x1000) #define KEY_CLOSE_WIN (KEY_INTERN+0) drawterm-20170818/gui-osx/load.c000066400000000000000000000002721314554504700163020ustar00rootroot00000000000000#include #include #include #include int loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) { return _loadmemimage(i, r, data, ndata); } drawterm-20170818/gui-osx/screen.c000066400000000000000000000452741314554504700166550ustar00rootroot00000000000000// in this file, _Rect is os x Rect, // _Point is os x Point #undef Point #define Point _Point #undef Rect #define Rect _Rect #include #include // for full screen #undef Rect #undef Point #undef nil #include "u.h" #include "lib.h" #include "kern/dat.h" #include "kern/fns.h" #include "error.h" #include "user.h" #include #include #include "screen.h" #include "keyboard.h" #include "keycodes.h" #define rWindowResource 128 #define topLeft(r) (((Point *) &(r))[0]) #define botRight(r) (((Point *) &(r))[1]) extern int mousequeue; static int depth; Boolean gDone; RgnHandle gCursorRegionHdl; Memimage *gscreen; Screeninfo screen; static int readybit; static Rendez rend; /// // menu // static MenuRef windMenu; static MenuRef viewMenu; enum { kQuitCmd = 1, kFullScreenCmd = 2, }; static WindowGroupRef winGroup = NULL; static WindowRef theWindow = NULL; static CGContextRef context; static CGDataProviderRef dataProviderRef; static CGImageRef fullScreenImage; static CGRect devRect; static CGRect bounds; static PasteboardRef appleclip; static _Rect winRect; Boolean altPressed = false; Boolean button2 = false; Boolean button3 = false; static int isready(void*a) { return readybit; } CGContextRef QuartzContext; void winproc(void *a); void screeninit(void) { int fmt; int dx, dy; ProcessSerialNumber psn = { 0, kCurrentProcess }; TransformProcessType(&psn, kProcessTransformToForegroundApplication); SetFrontProcess(&psn); memimageinit(); depth = 32; // That's all this code deals with for now screen.depth = 32; fmt = XBGR32; //XRGB32; devRect = CGDisplayBounds(CGMainDisplayID()); // devRect.origin.x = 0; // devRect.origin.y = 0; // devRect.size.width = 1024; // devRect.size.height = 768; dx = devRect.size.width; dy = devRect.size.height; gscreen = allocmemimage(Rect(0,0,dx,dy), fmt); dataProviderRef = CGDataProviderCreateWithData(0, gscreen->data->bdata, dx * dy * 4, 0); fullScreenImage = CGImageCreate(dx, dy, 8, 32, dx * 4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipLast, dataProviderRef, 0, 0, kCGRenderingIntentDefault); kproc("osxscreen", winproc, 0); ksleep(&rend, isready, 0); } // No wonder Apple sells so many wide displays! static OSStatus ApplicationQuitEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData); static OSStatus MainWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData); static OSStatus MainWindowCommandHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData); void window_resized() { GetWindowBounds(theWindow, kWindowContentRgn, &winRect ); bounds = CGRectMake(0, 0, winRect.right-winRect.left, winRect.bottom - winRect.top); } void winproc(void *a) { winRect.left = 30; winRect.top = 60; winRect.bottom = (devRect.size.height * 0.75) + winRect.top; winRect.right = (devRect.size.width * 0.75) + winRect.left; ClearMenuBar(); InitCursor(); CreateStandardWindowMenu(0, &windMenu); InsertMenu(windMenu, 0); MenuItemIndex index; CreateNewMenu(1004, 0, &viewMenu); SetMenuTitleWithCFString(viewMenu, CFSTR("View")); AppendMenuItemTextWithCFString(viewMenu, CFSTR("Full Screen"), 0, kFullScreenCmd, &index); SetMenuItemCommandKey(viewMenu, index, 0, 'F'); InsertMenu(viewMenu, GetMenuID(windMenu)); DrawMenuBar(); uint32_t windowAttrs = 0 | kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute | kWindowResizableAttribute | kWindowStandardHandlerAttribute | kWindowFullZoomAttribute ; CreateNewWindow(kDocumentWindowClass, windowAttrs, &winRect, &theWindow); CreateWindowGroup(0, &winGroup); SetWindowGroup(theWindow, winGroup); SetWindowTitleWithCFString(theWindow, CFSTR("Drawterm")); if(PasteboardCreate(kPasteboardClipboard, &appleclip) != noErr) sysfatal("pasteboard create failed"); const EventTypeSpec quit_events[] = { { kEventClassApplication, kEventAppQuit } }; const EventTypeSpec commands[] = { { kEventClassWindow, kEventWindowClosed }, { kEventClassWindow, kEventWindowBoundsChanged }, { kEventClassCommand, kEventCommandProcess } }; const EventTypeSpec events[] = { { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyModifiersChanged }, { kEventClassKeyboard, kEventRawKeyRepeat }, { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseUp }, { kEventClassMouse, kEventMouseMoved }, { kEventClassMouse, kEventMouseDragged }, { kEventClassMouse, kEventMouseWheelMoved }, }; InstallApplicationEventHandler ( NewEventHandlerUPP (ApplicationQuitEventHandler), GetEventTypeCount(quit_events), quit_events, NULL, NULL); InstallApplicationEventHandler ( NewEventHandlerUPP (MainWindowEventHandler), GetEventTypeCount(events), events, NULL, NULL); InstallWindowEventHandler ( theWindow, NewEventHandlerUPP (MainWindowCommandHandler), GetEventTypeCount(commands), commands, theWindow, NULL); ShowWindow(theWindow); ShowMenuBar(); window_resized(); SelectWindow(theWindow); terminit(); // Run the event loop readybit = 1; wakeup(&rend); RunApplicationEventLoop(); } static inline int convert_key(UInt32 key, UInt32 charcode) { switch(key) { case QZ_IBOOK_ENTER: case QZ_RETURN: return '\n'; case QZ_ESCAPE: return 27; case QZ_BACKSPACE: return '\b'; case QZ_LALT: return Kalt; case QZ_LCTRL: return Kctl; case QZ_LSHIFT: return Kshift; case QZ_F1: return KF+1; case QZ_F2: return KF+2; case QZ_F3: return KF+3; case QZ_F4: return KF+4; case QZ_F5: return KF+5; case QZ_F6: return KF+6; case QZ_F7: return KF+7; case QZ_F8: return KF+8; case QZ_F9: return KF+9; case QZ_F10: return KF+10; case QZ_F11: return KF+11; case QZ_F12: return KF+12; case QZ_INSERT: return Kins; case QZ_DELETE: return 0x7F; case QZ_HOME: return Khome; case QZ_END: return Kend; case QZ_KP_PLUS: return '+'; case QZ_KP_MINUS: return '-'; case QZ_TAB: return '\t'; case QZ_PAGEUP: return Kpgup; case QZ_PAGEDOWN: return Kpgdown; case QZ_UP: return Kup; case QZ_DOWN: return Kdown; case QZ_LEFT: return Kleft; case QZ_RIGHT: return Kright; case QZ_KP_MULTIPLY: return '*'; case QZ_KP_DIVIDE: return '/'; case QZ_KP_ENTER: return '\n'; case QZ_KP_PERIOD: return '.'; case QZ_KP0: return '0'; case QZ_KP1: return '1'; case QZ_KP2: return '2'; case QZ_KP3: return '3'; case QZ_KP4: return '4'; case QZ_KP5: return '5'; case QZ_KP6: return '6'; case QZ_KP7: return '7'; case QZ_KP8: return '8'; case QZ_KP9: return '9'; default: return charcode; } } void sendbuttons(int b, int x, int y) { int i; lock(&mouse.lk); i = mouse.wi; if(mousequeue) { if(i == mouse.ri || mouse.lastb != b || mouse.trans) { mouse.wi = (i+1)%Mousequeue; if(mouse.wi == mouse.ri) mouse.ri = (mouse.ri+1)%Mousequeue; mouse.trans = mouse.lastb != b; } else { i = (i-1+Mousequeue)%Mousequeue; } } else { mouse.wi = (i+1)%Mousequeue; mouse.ri = i; } mouse.queue[i].xy.x = x; mouse.queue[i].xy.y = y; mouse.queue[i].buttons = b; mouse.queue[i].msec = ticks(); mouse.lastb = b; unlock(&mouse.lk); wakeup(&mouse.r); } static Ptr fullScreenRestore; static int amFullScreen = 0; static WindowRef oldWindow = NULL; static void leave_full_screen() { if (amFullScreen) { EndFullScreen(fullScreenRestore, 0); theWindow = oldWindow; ShowWindow(theWindow); amFullScreen = 0; window_resized(); Rectangle rect = { { 0, 0 }, { bounds.size.width, bounds.size.height} }; drawqlock(); flushmemscreen(rect); drawqunlock(); } } static void full_screen() { if (!amFullScreen) { oldWindow = theWindow; HideWindow(theWindow); BeginFullScreen(&fullScreenRestore, 0, 0, 0, &theWindow, 0, 0); amFullScreen = 1; window_resized(); Rectangle rect = { { 0, 0 }, { bounds.size.width, bounds.size.height} }; drawqlock(); flushmemscreen(rect); drawqunlock(); } } // catch quit events to handle quits from menu, Cmd+Q, applescript, and task switcher static OSStatus ApplicationQuitEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData) { exit(0); // QuitApplicationEventLoop(); return noErr; } static OSStatus MainWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData) { OSStatus result = noErr; result = CallNextEventHandler(nextHandler, event); UInt32 class = GetEventClass (event); UInt32 kind = GetEventKind (event); static uint32_t mousebuttons = 0; // bitmask of buttons currently down static uint32_t mouseX = 0; static uint32_t mouseY = 0; if(class == kEventClassKeyboard) { char macCharCodes; UInt32 macKeyCode; UInt32 macKeyModifiers; GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(macCharCodes), NULL, &macCharCodes); GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(macKeyCode), NULL, &macKeyCode); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(macKeyModifiers), NULL, &macKeyModifiers); switch(kind) { case kEventRawKeyModifiersChanged: if (macKeyModifiers == (controlKey | optionKey)) leave_full_screen(); switch(macKeyModifiers & (optionKey | cmdKey)) { case (optionKey | cmdKey): /* due to chording we need to handle the case when both * modifier keys are pressed at the same time. * currently it's only 2-3 snarf and the 3-2 noop */ altPressed = true; if(mousebuttons & 1 || mousebuttons & 2 || mousebuttons & 4) { mousebuttons |= 2; /* set button 2 */ mousebuttons |= 4; /* set button 3 */ button2 = true; button3 = true; sendbuttons(mousebuttons, mouseX, mouseY); } break; case optionKey: altPressed = true; if(mousebuttons & 1 || mousebuttons & 4) { mousebuttons |= 2; /* set button 2 */ button2 = true; sendbuttons(mousebuttons, mouseX, mouseY); } break; case cmdKey: if(mousebuttons & 1 || mousebuttons & 2) { mousebuttons |= 4; /* set button 3 */ button3 = true; sendbuttons(mousebuttons, mouseX, mouseY); } break; case 0: default: if(button2 || button3) { if(button2) { mousebuttons &= ~2; /* clear button 2 */ button2 = false; altPressed = false; } if(button3) { mousebuttons &= ~4; /* clear button 3 */ button3 = false; } sendbuttons(mousebuttons, mouseX, mouseY); } if(altPressed) { kbdputc(kbdq, Kalt); altPressed = false; } break; } break; case kEventRawKeyDown: case kEventRawKeyRepeat: if(macKeyModifiers != cmdKey) { int key = convert_key(macKeyCode, macCharCodes); if (key != -1) kbdputc(kbdq, key); } else result = eventNotHandledErr; break; default: break; } } else if(class == kEventClassMouse) { _Point mousePos; GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, sizeof mousePos, 0, &mousePos); switch (kind) { case kEventMouseWheelMoved: { int32_t wheeldelta; GetEventParameter(event,kEventParamMouseWheelDelta,typeSInt32, 0,sizeof(wheeldelta), 0, &wheeldelta); mouseX = mousePos.h - winRect.left; mouseY = mousePos.v - winRect.top; sendbuttons(wheeldelta>0 ? 8 : 16, mouseX, mouseY); break; } case kEventMouseUp: case kEventMouseDown: { uint32_t buttons; uint32_t modifiers; GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, 0, sizeof(modifiers), 0, &modifiers); GetEventParameter(event, kEventParamMouseChord, typeUInt32, 0, sizeof buttons, 0, &buttons); /* simulate other buttons via alt/apple key. like x11 */ if(modifiers & optionKey) { mousebuttons = ((buttons & 1) ? 2 : 0); altPressed = false; } else if(modifiers & cmdKey) mousebuttons = ((buttons & 1) ? 4 : 0); else mousebuttons = (buttons & 1); mousebuttons |= ((buttons & 2)<<1); mousebuttons |= ((buttons & 4)>>1); } /* Fallthrough */ case kEventMouseMoved: case kEventMouseDragged: mouseX = mousePos.h - winRect.left; mouseY = mousePos.v - winRect.top; sendbuttons(mousebuttons, mouseX, mouseY); break; default: result = eventNotHandledErr; break; } } return result; } //default window command handler (from menus) static OSStatus MainWindowCommandHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData) { OSStatus result = noErr; UInt32 class = GetEventClass (event); UInt32 kind = GetEventKind (event); result = CallNextEventHandler(nextHandler, event); if(class == kEventClassCommand) { HICommand theHICommand; GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, sizeof( HICommand ), NULL, &theHICommand ); switch ( theHICommand.commandID ) { case kHICommandQuit: exit(0); break; case kFullScreenCmd: full_screen(); break; default: result = eventNotHandledErr; break; } } else if(class == kEventClassWindow) { WindowRef window; _Rect rectPort = {0,0,0,0}; GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window); if(window) { GetPortBounds(GetWindowPort(window), &rectPort); } switch (kind) { case kEventWindowClosed: // send a quit carbon event instead of directly calling cleanexit // so that all quits are done in ApplicationQuitEventHandler { EventRef quitEvent; CreateEvent(NULL, kEventClassApplication, kEventAppQuit, 0, kEventAttributeNone, &quitEvent); EventTargetRef target; target = GetApplicationEventTarget(); SendEventToEventTarget(quitEvent, target); } break; //resize window case kEventWindowBoundsChanged: window_resized(); Rectangle rect = { { 0, 0 }, { bounds.size.width, bounds.size.height} }; drawqlock(); flushmemscreen(rect); drawqunlock(); break; default: result = eventNotHandledErr; break; } } return result; } void flushmemscreen(Rectangle r) { // sanity check. Trips from the initial "terminal" if (r.max.x < r.min.x || r.max.y < r.min.y) return; screenload(r, gscreen->depth, byteaddr(gscreen, ZP), ZP, gscreen->width*sizeof(ulong)); } uchar* attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen, void **X) { *r = gscreen->r; *chan = gscreen->chan; *depth = gscreen->depth; *width = gscreen->width; *softscreen = 1; return gscreen->data->bdata; } // PAL - no palette handling. Don't intend to either. void getcolor(ulong i, ulong *r, ulong *g, ulong *b) { // PAL: Certainly wrong to return a grayscale. *r = i; *g = i; *b = i; } void setcolor(ulong index, ulong red, ulong green, ulong blue) { assert(0); } static char snarf[3*SnarfSize+1]; static Rune rsnarf[SnarfSize+1]; char* clipread(void) { CFDataRef cfdata; OSStatus err = noErr; ItemCount nItems; // Wow. This is ridiculously complicated. PasteboardSynchronize(appleclip); if((err = PasteboardGetItemCount(appleclip, &nItems)) != noErr) { fprint(2, "apple pasteboard GetItemCount failed - Error %d\n", err); return 0; } uint32_t i; // Yes, based at 1. Silly API. for(i = 1; i <= nItems; ++i) { PasteboardItemID itemID; CFArrayRef flavorTypeArray; CFIndex flavorCount; if((err = PasteboardGetItemIdentifier(appleclip, i, &itemID)) != noErr){ fprint(2, "Can't get pasteboard item identifier: %d\n", err); return 0; } if((err = PasteboardCopyItemFlavors(appleclip, itemID, &flavorTypeArray))!=noErr){ fprint(2, "Can't copy pasteboard item flavors: %d\n", err); return 0; } flavorCount = CFArrayGetCount(flavorTypeArray); CFIndex flavorIndex; for(flavorIndex = 0; flavorIndex < flavorCount; ++flavorIndex){ CFStringRef flavorType; flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex); if (UTTypeConformsTo(flavorType, CFSTR("public.utf16-plain-text"))){ if((err = PasteboardCopyItemFlavorData(appleclip, itemID, CFSTR("public.utf16-plain-text"), &cfdata)) != noErr){ fprint(2, "apple pasteboard CopyItem failed - Error %d\n", err); return 0; } CFIndex length = CFDataGetLength(cfdata); if (length > sizeof rsnarf) length = sizeof rsnarf; CFDataGetBytes(cfdata, CFRangeMake(0, length), (uint8_t *)rsnarf); snprint(snarf, sizeof snarf, "%.*S", length/sizeof(Rune), rsnarf); char *s = snarf; while (*s) { if (*s == '\r') *s = '\n'; s++; } CFRelease(cfdata); return strdup(snarf); } } } return 0; } int clipwrite(char *snarf) { CFDataRef cfdata; PasteboardSyncFlags flags; runesnprint(rsnarf, nelem(rsnarf), "%s", snarf); if(PasteboardClear(appleclip) != noErr){ fprint(2, "apple pasteboard clear failed\n"); return 0; } flags = PasteboardSynchronize(appleclip); if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){ fprint(2, "apple pasteboard cannot assert ownership\n"); return 0; } cfdata = CFDataCreate(kCFAllocatorDefault, (uchar*)rsnarf, runestrlen(rsnarf)*2); if(cfdata == nil){ fprint(2, "apple pasteboard cfdatacreate failed\n"); return 0; } if(PasteboardPutItemFlavor(appleclip, (PasteboardItemID)1, CFSTR("public.utf16-plain-text"), cfdata, 0) != noErr){ fprint(2, "apple pasteboard putitem failed\n"); CFRelease(cfdata); return 0; } CFRelease(cfdata); return 1; } void mouseset(Point xy) { CGPoint pnt; pnt.x = xy.x + winRect.left; pnt.y = xy.y + winRect.top; CGWarpMouseCursorPosition(pnt); } void screenload(Rectangle r, int depth, uchar *p, Point pt, int step) { CGRect rbounds; rbounds.size.width = r.max.x - r.min.x; rbounds.size.height = r.max.y - r.min.y; rbounds.origin.x = r.min.x; rbounds.origin.y = r.min.y; if(depth != gscreen->depth) panic("screenload: bad ldepth"); QDBeginCGContext( GetWindowPort(theWindow), &context); // The sub-image is relative to our whole screen image. CGImageRef subimg = CGImageCreateWithImageInRect(fullScreenImage, rbounds); // Drawing the sub-image is relative to the window. rbounds.origin.y = winRect.bottom - winRect.top - r.min.y - rbounds.size.height; CGContextDrawImage(context, rbounds, subimg); CGContextFlush(context); CGImageRelease(subimg); QDEndCGContext( GetWindowPort(theWindow), &context); } // PAL: these don't work. // SetCursor and InitCursor are marked as deprecated in 10.4, and I can't for the // life of me find out what has replaced them. void setcursor(void) { Cursor crsr; int i; for(i=0; i<16; i++){ crsr.data[i] = ((ushort*)cursor.set)[i]; crsr.mask[i] = crsr.data[i] | ((ushort*)cursor.clr)[i]; } crsr.hotSpot.h = -cursor.offset.x; crsr.hotSpot.v = -cursor.offset.y; SetCursor(&crsr); } void cursorarrow(void) { InitCursor(); } drawterm-20170818/gui-osx/wstrtoutf.c000066400000000000000000000006301314554504700174420ustar00rootroot00000000000000#include #include int wstrutflen(Rune *s) { int n; for(n=0; *s; n+=runelen(*s),s++) ; return n; } int wstrtoutf(char *s, Rune *t, int n) { int i; char *s0; s0 = s; if(n <= 0) return wstrutflen(t)+1; while(*t) { if(n < UTFmax+1 && n < runelen(*t)+1) { *s = 0; return i+wstrutflen(t)+1; } i = runetochar(s, t); s += i; n -= i; t++; } *s = 0; return s-s0; } drawterm-20170818/gui-win32/000077500000000000000000000000001314554504700153475ustar00rootroot00000000000000drawterm-20170818/gui-win32/Makefile000066400000000000000000000003451314554504700170110ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libgui.a OFILES=\ alloc.$O\ cload.$O\ draw.$O\ load.$O\ screen.$O\ r16.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/gui-win32/alloc.c000066400000000000000000000004361314554504700166100ustar00rootroot00000000000000#include #include #include #include Memimage* allocmemimage(Rectangle r, ulong chan) { return _allocmemimage(r, chan); } void freememimage(Memimage *i) { _freememimage(i); } void memfillcolor(Memimage *i, ulong val) { _memfillcolor(i, val); } drawterm-20170818/gui-win32/cload.c000066400000000000000000000002741314554504700166000ustar00rootroot00000000000000#include #include #include #include int cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) { return _cloadmemimage(i, r, data, ndata); } drawterm-20170818/gui-win32/draw.c000066400000000000000000000005551314554504700164550ustar00rootroot00000000000000#include #include #include #include void memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op) { _memimagedraw(_memimagedrawsetup(dst, r, src, sp, mask, mp, op)); } ulong pixelbits(Memimage *m, Point p) { return _pixelbits(m, p); } void memimageinit(void) { _memimageinit(); } drawterm-20170818/gui-win32/load.c000066400000000000000000000002721314554504700164330ustar00rootroot00000000000000#include #include #include #include int loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) { return _loadmemimage(i, r, data, ndata); } drawterm-20170818/gui-win32/r16.c000066400000000000000000000042401314554504700161230ustar00rootroot00000000000000#define _WIN32_WINNT 0x0500 #include #include #include #include "r16.h" #define Bit(i) (7-(i)) /* N 0's preceded by i 1's, T(Bit(2)) is 1100 0000 */ #define T(i) (((1 << (Bit(i)+1))-1) ^ 0xFF) /* 0000 0000 0000 0111 1111 1111 */ #define RuneX(i) ((1 << (Bit(i) + ((i)-1)*Bitx))-1) enum { Bitx = Bit(1), Tx = T(1), /* 1000 0000 */ Rune1 = (1<<(Bit(0)+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */ Maskx = (1<= Runeself) n = runelen(c); if(p + n >= ep) break; rc = c; if(c < Runeself) *p++ = c; else p += runetochar(p, &rc); } *p = '\0'; return op; } int rune16nlen(Rune16 *r, int nrune) { int nb, i; Rune c; nb = 0; while(nrune--) { c = *r++; if(c <= Rune1){ nb++; } else { for(i = 2; i < UTFmax + 1; i++) if(c <= RuneX(i) || i == UTFmax){ nb += i; break; } } } return nb; } Rune16* utftorunes16(Rune16 *r, char *p, int nc) { Rune16 *or, *er; Rune rc; or = r; er = r + nc; while(*p != '\0' && r + 1 < er){ p += chartorune(&rc, p); *r++ = rc; /* we'll ignore surrogate pairs */ } *r = '\0'; return or; } int runes16cmp(Rune16 *s1, Rune16 *s2) { Rune16 r1, r2; for(;;) { r1 = *s1++; r2 = *s2++; if(r1 != r2) { if(r1 > r2) return 1; return -1; } if(r1 == 0) return 0; } } wchar_t * widen(char *s) { int n; wchar_t *ws; n = utflen(s) + 1; ws = smalloc(n*sizeof(wchar_t)); utftorunes16(ws, s, n); return ws; } char * narrowen(wchar_t *ws) { char *s; int n; n = widebytes(ws); s = smalloc(n); runes16toutf(s, ws, n); return s; } int widebytes(wchar_t *ws) { int n = 0; while (*ws) n += runelen(*ws++); return n+1; } drawterm-20170818/gui-win32/r16.h000066400000000000000000000005011314554504700161240ustar00rootroot00000000000000typedef unsigned short Rune16; wchar_t *widen(char *s); char *narrowen(wchar_t *ws); int widebytes(wchar_t *ws); int runes16len(Rune16*); int rune16nlen(Rune16*, int); Rune16* runes16dup(Rune16*); Rune16* utftorunes16(Rune16*, char*, int); char* runes16toutf(char*, Rune16*, int); int runes16cmp(Rune16*, Rune16*); drawterm-20170818/gui-win32/screen.c000066400000000000000000000302561314554504700170000ustar00rootroot00000000000000#define _WIN32_WINNT 0x0500 #include #undef Rectangle #define Rectangle _Rectangle #include "u.h" #include "lib.h" #include "kern/dat.h" #include "kern/fns.h" #include "error.h" #include "user.h" #include #include #include "screen.h" #include "keyboard.h" #include "r16.h" Memimage *gscreen; Screeninfo screen; extern int mousequeue; static int depth; static HINSTANCE inst; static HWND window; static HPALETTE palette; static LOGPALETTE *logpal; static Lock gdilock; static BITMAPINFO *bmi; static HCURSOR hcursor; static void winproc(void *); static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); static void paletteinit(void); static void bmiinit(void); static int readybit; static Rendez rend; Point ZP; uint windowStyle; const uint BORDERLESS = WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME | WS_SYSMENU | WS_DLGFRAME | WS_CLIPSIBLINGS | WS_VISIBLE | WS_POPUP ^ WS_MINIMIZE | WS_MAXIMIZE; static int isready(void*a) { return readybit; } void screeninit(void) { int fmt; int dx, dy; memimageinit(); if(depth == 0) depth = GetDeviceCaps(GetDC(NULL), BITSPIXEL); switch(depth){ case 32: screen.dibtype = DIB_RGB_COLORS; screen.depth = 32; fmt = XRGB32; break; case 24: screen.dibtype = DIB_RGB_COLORS; screen.depth = 24; fmt = RGB24; break; case 16: screen.dibtype = DIB_RGB_COLORS; screen.depth = 16; fmt = RGB15; /* [sic] */ break; case 8: default: screen.dibtype = DIB_PAL_COLORS; screen.depth = 8; depth = 8; fmt = CMAP8; break; } dx = GetDeviceCaps(GetDC(NULL), HORZRES); dy = GetDeviceCaps(GetDC(NULL), VERTRES); gscreen = allocmemimage(Rect(0,0,dx,dy), fmt); kproc("winscreen", winproc, 0); ksleep(&rend, isready, 0); } uchar* attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen, void **X) { *r = gscreen->r; *chan = gscreen->chan; *depth = gscreen->depth; *width = gscreen->width; *softscreen = 1; return gscreen->data->bdata; } void flushmemscreen(Rectangle r) { screenload(r, gscreen->depth, byteaddr(gscreen, ZP), ZP, gscreen->width*sizeof(ulong)); // Sleep(100); } void screenload(Rectangle r, int depth, uchar *p, Point pt, int step) { int dx, dy, delx; HDC hdc; RECT winr; if(depth != gscreen->depth) panic("screenload: bad ldepth"); /* * Sometimes we do get rectangles that are off the * screen to the negative axes, for example, when * dragging around a window border in a Move operation. */ if(rectclip(&r, gscreen->r) == 0) return; if((step&3) != 0 || ((pt.x*depth)%32) != 0 || ((ulong)p&3) != 0) panic("screenload: bad params %d %d %ux", step, pt.x, p); dx = r.max.x - r.min.x; dy = r.max.y - r.min.y; if(dx <= 0 || dy <= 0) return; if(depth == 24) delx = r.min.x % 4; else delx = r.min.x & (31/depth); p += (r.min.y-pt.y)*step; p += ((r.min.x-delx-pt.x)*depth)>>3; if(GetWindowRect(window, &winr)==0) return; if(rectclip(&r, Rect(0, 0, winr.right-winr.left, winr.bottom-winr.top))==0) return; lock(&gdilock); hdc = GetDC(window); SelectPalette(hdc, palette, 0); RealizePalette(hdc); //FillRect(hdc,(void*)&r, GetStockObject(BLACK_BRUSH)); //GdiFlush(); //Sleep(100); bmi->bmiHeader.biWidth = (step*8)/depth; bmi->bmiHeader.biHeight = -dy; /* - => origin upper left */ StretchDIBits(hdc, r.min.x, r.min.y, dx, dy, delx, 0, dx, dy, p, bmi, screen.dibtype, SRCCOPY); ReleaseDC(window, hdc); GdiFlush(); unlock(&gdilock); } static void winproc(void *a) { WNDCLASS wc; MSG msg; inst = GetModuleHandle(NULL); paletteinit(); bmiinit(); terminit(); wc.style = 0; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = inst; wc.hIcon = LoadIcon(inst, NULL); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = 0; wc.lpszClassName = L"9pmgraphics"; RegisterClass(&wc); windowStyle = WS_OVERLAPPEDWINDOW; window = CreateWindowEx( 0, /* extended style */ L"9pmgraphics", /* class */ L"drawterm screen", /* caption */ windowStyle, /* style */ CW_USEDEFAULT, /* init. x pos */ CW_USEDEFAULT, /* init. y pos */ CW_USEDEFAULT, /* init. x size */ CW_USEDEFAULT, /* init. y size */ NULL, /* parent window (actually owner window for overlapped)*/ NULL, /* menu handle */ inst, /* program handle */ NULL /* create parms */ ); if(window == nil) panic("can't make window\n"); ShowWindow(window, SW_SHOWDEFAULT); UpdateWindow(window); readybit = 1; wakeup(&rend); screen.reshaped = 0; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // MessageBox(0, "winproc", "exits", MB_OK); ExitProcess(0); } int col(int v, int n) { int i, c; c = 0; for(i = 0; i < 8; i += n) c |= v << (16-(n+i)); return c >> 8; } void paletteinit(void) { PALETTEENTRY *pal; int r, g, b, cr, cg, cb, v; int num, den; int i, j; logpal = mallocz(sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY), 1); if(logpal == nil) panic("out of memory"); logpal->palVersion = 0x300; logpal->palNumEntries = 256; pal = logpal->palPalEntry; for(r=0,i=0; r<4; r++) { for(v=0; v<4; v++,i+=16){ for(g=0,j=v-r; g<4; g++) { for(b=0; b<4; b++,j++){ den=r; if(g>den) den=g; if(b>den) den=b; /* divide check -- pick grey shades */ if(den==0) cr=cg=cb=v*17; else{ num=17*(4*den+v); cr=r*num/den; cg=g*num/den; cb=b*num/den; } pal[i+(j&15)].peRed = cr; pal[i+(j&15)].peGreen = cg; pal[i+(j&15)].peBlue = cb; pal[i+(j&15)].peFlags = 0; } } } } palette = CreatePalette(logpal); } void getcolor(ulong i, ulong *r, ulong *g, ulong *b) { PALETTEENTRY *pal; pal = logpal->palPalEntry; *r = pal[i].peRed; *g = pal[i].peGreen; *b = pal[i].peBlue; } void bmiinit(void) { ushort *p; int i; bmi = mallocz(sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD), 1); if(bmi == 0) panic("out of memory"); bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi->bmiHeader.biWidth = 0; bmi->bmiHeader.biHeight = 0; /* - => origin upper left */ bmi->bmiHeader.biPlanes = 1; bmi->bmiHeader.biBitCount = depth; bmi->bmiHeader.biCompression = BI_RGB; bmi->bmiHeader.biSizeImage = 0; bmi->bmiHeader.biXPelsPerMeter = 0; bmi->bmiHeader.biYPelsPerMeter = 0; bmi->bmiHeader.biClrUsed = 0; bmi->bmiHeader.biClrImportant = 0; /* number of important colors: 0 means all */ p = (ushort*)bmi->bmiColors; for(i = 0; i < 256; i++) p[i] = i; } LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { PAINTSTRUCT paint; HDC hdc; LONG x, y, b; int i; Rectangle r; b = 0; switch(msg) { case WM_CREATE: break; case WM_SETCURSOR: /* User set */ if(hcursor != NULL) { SetCursor(hcursor); return 1; } return DefWindowProc(hwnd, msg, wparam, lparam); case WM_MOUSEWHEEL: if ((int)(wparam & 0xFFFF0000)>0) b|=8; else b|=16; case WM_MOUSEMOVE: case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: x = LOWORD(lparam); y = HIWORD(lparam); if(wparam & MK_LBUTTON) b = 1; if(wparam & MK_MBUTTON) b |= 2; if(wparam & MK_RBUTTON) { if(wparam & MK_SHIFT) b |= 2; else b |= 4; } lock(&mouse.lk); i = mouse.wi; if(mousequeue) { if(i == mouse.ri || mouse.lastb != b || mouse.trans) { mouse.wi = (i+1)%Mousequeue; if(mouse.wi == mouse.ri) mouse.ri = (mouse.ri+1)%Mousequeue; mouse.trans = mouse.lastb != b; } else { i = (i-1+Mousequeue)%Mousequeue; } } else { mouse.wi = (i+1)%Mousequeue; mouse.ri = i; } mouse.queue[i].xy.x = x; mouse.queue[i].xy.y = y; mouse.queue[i].buttons = b; mouse.queue[i].msec = ticks(); mouse.lastb = b; unlock(&mouse.lk); wakeup(&mouse.r); break; case WM_CHAR: /* repeat count is lparam & 0xf */ switch(wparam){ case '\n': wparam = '\r'; break; case '\r': wparam = '\n'; break; } kbdputc(kbdq, wparam); break; case WM_SYSKEYUP: break; case WM_SYSKEYDOWN: case WM_KEYDOWN: switch(wparam) { case VK_MENU: kbdputc(kbdq, Kalt); break; case VK_INSERT: kbdputc(kbdq, Kins); break; case VK_DELETE: kbdputc(kbdq, Kdel); break; case VK_HOME: kbdputc(kbdq, Khome); break; case VK_END: kbdputc(kbdq, Kend); break; case VK_PRIOR: kbdputc(kbdq, Kpgup); break; case VK_NEXT: kbdputc(kbdq, Kpgdown); break; case VK_UP: kbdputc(kbdq, Kup); break; case VK_DOWN: kbdputc(kbdq, Kdown); break; case VK_LEFT: kbdputc(kbdq, Kleft); break; case VK_RIGHT: kbdputc(kbdq, Kright); break; case VK_F11: if (windowStyle == WS_OVERLAPPEDWINDOW) windowStyle = BORDERLESS; else windowStyle = WS_OVERLAPPEDWINDOW; SetWindowLongPtr(hwnd, -16, windowStyle); ShowWindow(hwnd, SW_SHOWNORMAL); RECT rcWnd; GetWindowRect(hwnd,&rcWnd); SetWindowPos(hwnd,(HWND)0,rcWnd.left,rcWnd.top,(rcWnd.right-rcWnd.left),(rcWnd.bottom-rcWnd.top),SWP_NOMOVE); /* forces a refresh of the screen */ ShowWindow(hwnd, SW_SHOWMAXIMIZED); } break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_PALETTECHANGED: if((HWND)wparam == hwnd) break; /* fall through */ case WM_QUERYNEWPALETTE: hdc = GetDC(hwnd); SelectPalette(hdc, palette, 0); if(RealizePalette(hdc) != 0) InvalidateRect(hwnd, nil, 0); ReleaseDC(hwnd, hdc); break; case WM_PAINT: hdc = BeginPaint(hwnd, &paint); r.min.x = paint.rcPaint.left; r.min.y = paint.rcPaint.top; r.max.x = paint.rcPaint.right; r.max.y = paint.rcPaint.bottom; flushmemscreen(r); EndPaint(hwnd, &paint); break; case WM_COMMAND: case WM_SETFOCUS: case WM_DEVMODECHANGE: case WM_WININICHANGE: case WM_INITMENU: default: return DefWindowProc(hwnd, msg, wparam, lparam); } return 0; } void mouseset(Point xy) { POINT pt; pt.x = xy.x; pt.y = xy.y; MapWindowPoints(window, 0, &pt, 1); SetCursorPos(pt.x, pt.y); } void setcursor(void) { HCURSOR nh; int x, y, h, w; uchar *sp, *cp; uchar *and, *xor; h = GetSystemMetrics(SM_CYCURSOR); w = (GetSystemMetrics(SM_CXCURSOR)+7)/8; and = mallocz(h*w, 1); memset(and, 0xff, h*w); xor = mallocz(h*w, 1); lock(&cursor.lk); for(y=0,sp=cursor.set,cp=cursor.clr; y<16; y++) { for(x=0; x<2; x++) { and[y*w+x] = ~(*sp|*cp); xor[y*w+x] = ~*sp & *cp; cp++; sp++; } } nh = CreateCursor(inst, -cursor.offset.x, -cursor.offset.y, GetSystemMetrics(SM_CXCURSOR), h, and, xor); if(nh != NULL) { SetCursor(nh); if(hcursor != NULL) DestroyCursor(hcursor); hcursor = nh; } unlock(&cursor.lk); free(and); free(xor); PostMessage(window, WM_SETCURSOR, (int)window, 0); } void cursorarrow(void) { if(hcursor != 0) { DestroyCursor(hcursor); hcursor = 0; } SetCursor(LoadCursor(0, IDC_ARROW)); PostMessage(window, WM_SETCURSOR, (int)window, 0); } void setcolor(ulong index, ulong red, ulong green, ulong blue) { } uchar* clipreadunicode(HANDLE h) { Rune16 *p; int n; uchar *q; p = GlobalLock(h); n = rune16nlen(p, runes16len(p)+1); q = malloc(n); runes16toutf(q, p, n); GlobalUnlock(h); return q; } uchar * clipreadutf(HANDLE h) { uchar *p; p = GlobalLock(h); p = strdup(p); GlobalUnlock(h); return p; } char* clipread(void) { HANDLE h; uchar *p; if(!OpenClipboard(window)) { oserror(); return strdup(""); } if((h = GetClipboardData(CF_UNICODETEXT))) p = clipreadunicode(h); else if((h = GetClipboardData(CF_TEXT))) p = clipreadutf(h); else { oserror(); p = strdup(""); } CloseClipboard(); return p; } int clipwrite(char *buf) { HANDLE h; char *p, *e; Rune16 *rp; int n = strlen(buf); if(!OpenClipboard(window)) { oserror(); return -1; } if(!EmptyClipboard()) { oserror(); CloseClipboard(); return -1; } h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, (n+1)*sizeof(Rune)); if(h == NULL) panic("out of memory"); rp = GlobalLock(h); utftorunes16(rp, buf, n+1); GlobalUnlock(h); SetClipboardData(CF_UNICODETEXT, h); h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, n+1); if(h == NULL) panic("out of memory"); p = GlobalLock(h); memcpy(p, buf, n); p[n] = 0; GlobalUnlock(h); SetClipboardData(CF_TEXT, h); CloseClipboard(); return n; } int atlocalconsole(void) { return 1; } drawterm-20170818/gui-x11/000077500000000000000000000000001314554504700150165ustar00rootroot00000000000000drawterm-20170818/gui-x11/Makefile000066400000000000000000000002421314554504700164540ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libgui.a OFILES=\ x11.$O\ keysym2ucs-x11.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) drawterm-20170818/gui-x11/keysym2ucs-x11.c000066400000000000000000002027001314554504700177100ustar00rootroot00000000000000/* $XFree86: xc/programs/xterm/keysym2ucs.c,v 1.5 2001/06/18 19:09:26 dickey Exp $ * This module converts keysym values into the corresponding ISO 10646 * (UCS, Unicode) values. * * The array keysymtab[] contains pairs of X11 keysym values for graphical * characters and the corresponding Unicode value. The function * keysym2ucs() maps a keysym onto a Unicode value using a binary search, * therefore keysymtab[] must remain SORTED by keysym value. * * The keysym -> UTF-8 conversion will hopefully one day be provided * by Xlib via XmbLookupString() and should ideally not have to be * done in X applications. But we are not there yet. * * We allow to represent any UCS character in the range U-00000000 to * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. * This admittedly does not cover the entire 31-bit space of UCS, but * it does cover all of the characters up to U-10FFFF, which can be * represented by UTF-16, and more, and it is very unlikely that higher * UCS codes will ever be assigned by ISO. So to get Unicode character * U+ABCD you can directly use keysym 0x0100abcd. * * NOTE: The comments in the table below contain the actual character * encoded in UTF-8, so for viewing and editing best use an editor in * UTF-8 mode. * * Author: Markus G. Kuhn , University of Cambridge, April 2001 * * Special thanks to Richard Verhoeven for preparing * an initial draft of the mapping table. * * This software is in the public domain. Share and enjoy! * * AUTOMATICALLY GENERATED FILE, DO NOT EDIT !!! (unicode/convmap.pl) */ #ifndef KEYSYM2UCS_INCLUDED #include "keysym2ucs.h" #define VISIBLE /* */ #else #define VISIBLE static #endif static struct codepair { unsigned short keysym; unsigned short ucs; } keysymtab[] = { { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ { 0x01a9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */ { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ { 0x01af, 0x017b }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */ { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ { 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */ { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ { 0x01b7, 0x02c7 }, /* caron ˇ CARON */ { 0x01b9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */ { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ { 0x01bb, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */ { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ { 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ { 0x01d9, 0x016e }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */ { 0x01db, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ { 0x01de, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */ { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ { 0x01fe, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */ { 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */ { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ { 0x02a9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */ { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ { 0x02ac, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ { 0x02b6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ { 0x02d5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */ { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ { 0x02f5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */ { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ { 0x02fd, 0x016d }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */ { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ { 0x03a6, 0x013b }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */ { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ { 0x03ab, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */ { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ { 0x03b5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */ { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ { 0x03bb, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */ { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */ { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ { 0x03c7, 0x012e }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */ { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ { 0x03ef, 0x012b }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */ { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ { 0x03f3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */ { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ { 0x03fd, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */ { 0x03fe, 0x016b }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */ { 0x047e, 0x203e }, /* overline ‾ OVERLINE */ { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ { 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */ { 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ { 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ { 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */ { 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */ { 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */ { 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */ { 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */ { 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */ { 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */ { 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */ { 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */ { 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ { 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ { 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */ { 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */ { 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */ { 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */ { 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */ { 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */ { 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */ { 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */ { 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */ { 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */ { 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */ { 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */ { 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */ { 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */ { 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */ { 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */ { 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */ { 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */ { 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */ { 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */ { 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */ { 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */ { 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */ { 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */ { 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */ { 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */ { 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */ { 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */ { 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */ { 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */ { 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */ { 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */ { 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */ { 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */ { 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */ { 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */ { 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */ { 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */ { 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */ { 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */ { 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */ { 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */ { 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */ { 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */ { 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */ { 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ { 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ { 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */ { 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ { 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ { 0x05c1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */ { 0x05c2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */ { 0x05c3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */ { 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ { 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */ { 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ { 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */ { 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */ { 0x05c9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */ { 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */ { 0x05cb, 0x062b }, /* Arabic_theh ث ARABIC LETTER THEH */ { 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */ { 0x05cd, 0x062d }, /* Arabic_hah ح ARABIC LETTER HAH */ { 0x05ce, 0x062e }, /* Arabic_khah خ ARABIC LETTER KHAH */ { 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */ { 0x05d0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */ { 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */ { 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */ { 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */ { 0x05d4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */ { 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */ { 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */ { 0x05d7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */ { 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */ { 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */ { 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */ { 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */ { 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */ { 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */ { 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */ { 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */ { 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */ { 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */ { 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */ { 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */ { 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ { 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */ { 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */ { 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ { 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */ { 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */ { 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */ { 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */ { 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */ { 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */ { 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ { 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ { 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ { 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ { 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ { 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ { 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ { 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ { 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ { 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ { 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */ { 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ { 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ { 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ { 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ { 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ { 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ { 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ { 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ { 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ { 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ { 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ { 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ { 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ { 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ { 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ { 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ { 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ { 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ { 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ { 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ { 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ { 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ { 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ { 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ { 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ { 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ { 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ { 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ { 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ { 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ { 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ { 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ { 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ { 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ { 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ { 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ { 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ { 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ { 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ { 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ { 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ { 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ { 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ { 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ { 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ { 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ { 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ { 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ { 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ { 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ { 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ { 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ { 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ { 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ { 0x06e8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */ { 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ { 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ { 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ { 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ { 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ { 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ { 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ { 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ { 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ { 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ { 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ { 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ { 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ { 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ { 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ { 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ { 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ { 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ { 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ { 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ { 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ { 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ { 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ { 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ { 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ { 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ { 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ { 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ { 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ { 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ { 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ { 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ { 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */ { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ { 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ { 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ { 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ { 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ { 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ { 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ { 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ { 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ { 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ { 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ { 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ { 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ { 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ { 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ { 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ { 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ { 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ { 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ { 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ { 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ { 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ { 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ { 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ { 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */ { 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ { 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ { 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ { 0x07d5, 0x03a5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */ { 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ { 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ { 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */ { 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ { 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */ { 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ { 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ { 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */ { 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */ { 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */ { 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ { 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ { 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */ { 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */ { 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */ { 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ { 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */ { 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */ { 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ { 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ { 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */ { 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ { 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */ { 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */ { 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */ { 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ { 0x08a1, 0x23b7 }, /* leftradical ⎷ ??? */ { 0x08a2, 0x250c }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ { 0x08a3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */ { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ { 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ ??? */ { 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ ??? */ { 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ ??? */ { 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ ??? */ { 0x08ab, 0x239b }, /* topleftparens ⎛ ??? */ { 0x08ac, 0x239d }, /* botleftparens ⎝ ??? */ { 0x08ad, 0x239e }, /* toprightparens ⎞ ??? */ { 0x08ae, 0x23a0 }, /* botrightparens ⎠ ??? */ { 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ ??? */ { 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ ??? */ /* 0x08b1 topleftsummation ? ??? */ /* 0x08b2 botleftsummation ? ??? */ /* 0x08b3 topvertsummationconnector ? ??? */ /* 0x08b4 botvertsummationconnector ? ??? */ /* 0x08b5 toprightsummation ? ??? */ /* 0x08b6 botrightsummation ? ??? */ /* 0x08b7 rightmiddlesummation ? ??? */ { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ { 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */ { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */ { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */ { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */ { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */ { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */ { 0x08c8, 0x223c }, /* approximate ∼ TILDE OPERATOR */ { 0x08c9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */ { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */ { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */ { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */ { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */ { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */ { 0x08dd, 0x222a }, /* union ∪ UNION */ { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */ { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */ { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ { 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */ { 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */ { 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */ { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ /* 0x09df blank ? ??? */ { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */ { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */ { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ { 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */ { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ { 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ { 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ { 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */ { 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */ { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ { 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */ { 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */ { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ { 0x0aa1, 0x2003 }, /* emspace   EM SPACE */ { 0x0aa2, 0x2002 }, /* enspace   EN SPACE */ { 0x0aa3, 0x2004 }, /* em3space   THREE-PER-EM SPACE */ { 0x0aa4, 0x2005 }, /* em4space   FOUR-PER-EM SPACE */ { 0x0aa5, 0x2007 }, /* digitspace   FIGURE SPACE */ { 0x0aa6, 0x2008 }, /* punctspace   PUNCTUATION SPACE */ { 0x0aa7, 0x2009 }, /* thinspace   THIN SPACE */ { 0x0aa8, 0x200a }, /* hairspace   HAIR SPACE */ { 0x0aa9, 0x2014 }, /* emdash — EM DASH */ { 0x0aaa, 0x2013 }, /* endash – EN DASH */ /* 0x0aac signifblank ? ??? */ { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ { 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */ { 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ { 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ { 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ { 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ { 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ { 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ { 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ { 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */ { 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */ { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ /* 0x0abd decimalpoint ? ??? */ { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ /* 0x0abf marker ? ??? */ { 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ { 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ { 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ { 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ { 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */ { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */ /* 0x0acb trademarkincircle ? ??? */ { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ { 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */ { 0x0acf, 0x25af }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */ { 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ { 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ { 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ { 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ { 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */ { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */ { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */ /* 0x0ada hexagram ? ??? */ { 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */ { 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ { 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */ { 0x0adf, 0x25ae }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */ { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */ { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ { 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */ { 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ { 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */ { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */ { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ { 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ { 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ { 0x0af1, 0x2020 }, /* dagger † DAGGER */ { 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */ { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */ { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */ { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */ { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */ { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ { 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ { 0x0afc, 0x2038 }, /* caret ‸ CARET */ { 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ { 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ /* 0x0aff cursor ? ??? */ { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */ { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */ { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */ { 0x0bc2, 0x22a5 }, /* downtack ⊥ UP TACK */ { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */ { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */ { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */ { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */ { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD */ { 0x0bce, 0x22a4 }, /* uptack ⊤ DOWN TACK */ { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */ { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */ { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ { 0x0bdc, 0x22a2 }, /* lefttack ⊢ RIGHT TACK */ { 0x0bfc, 0x22a3 }, /* righttack ⊣ LEFT TACK */ { 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */ { 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */ { 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */ { 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */ { 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */ { 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */ { 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */ { 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */ { 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */ { 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ { 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */ { 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */ { 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ { 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */ { 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ { 0x0cf0, 0x05e0 }, /* hebrew_nun נ HEBREW LETTER NUN */ { 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */ { 0x0cf2, 0x05e2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */ { 0x0cf3, 0x05e3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */ { 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */ { 0x0cf5, 0x05e5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */ { 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */ { 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */ { 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */ { 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */ { 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */ { 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */ { 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ { 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ { 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ { 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ { 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ { 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ { 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ { 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ { 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ { 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */ { 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ { 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */ { 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ { 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ { 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ { 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ { 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ { 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */ { 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */ { 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */ { 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ { 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ { 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */ { 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */ { 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ { 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */ { 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ { 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */ { 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ { 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ { 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ { 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */ { 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */ { 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */ { 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */ { 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */ { 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */ { 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ { 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */ { 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ { 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */ { 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */ { 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ { 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */ { 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ { 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ { 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */ { 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ { 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */ { 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */ { 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */ { 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */ { 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */ { 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ { 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */ { 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */ { 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ /* 0x0dde Thai_maihanakat_maitho ? ??? */ { 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ { 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */ { 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */ { 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */ { 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ { 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ { 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ { 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ { 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ { 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */ { 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */ { 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ { 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ { 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ { 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ { 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */ { 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */ { 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */ { 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */ { 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */ { 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */ { 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */ { 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ { 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ { 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */ { 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ { 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ { 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ { 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ { 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ { 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ { 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ { 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ { 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ { 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ { 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ { 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ { 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ { 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ { 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ { 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ { 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ { 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ { 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ { 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ { 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ { 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ { 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ { 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ { 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ { 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ { 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ { 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ { 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ { 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ { 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */ { 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */ { 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */ { 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ { 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */ { 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */ { 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ { 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */ { 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */ { 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */ { 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ { 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */ { 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */ { 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */ { 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ { 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */ { 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */ { 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */ { 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */ { 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */ { 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */ { 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ { 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ { 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ { 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ { 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ { 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ { 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ { 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ { 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ { 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ { 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ { 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ { 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ { 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ { 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ { 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ { 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ { 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ { 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ { 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ { 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ { 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ { 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ { 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ { 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ { 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ { 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ { 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ { 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ { 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ { 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ { 0x0ef3, 0x3181 }, /* Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */ { 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ { 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ { 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ { 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ { 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ { 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */ { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */ { 0x13a4, 0x20ac }, /* Euro € EURO SIGN */ { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */ }; VISIBLE long keysym2ucs(KeySym keysym) { int min = 0; int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; int mid; /* first check for Latin-1 characters (1:1 mapping) */ if ((keysym >= 0x0020 && keysym <= 0x007e) || (keysym >= 0x00a0 && keysym <= 0x00ff)) return keysym; /* also check for directly encoded 24-bit UCS characters */ if ((keysym & 0xff000000) == 0x01000000) return keysym & 0x00ffffff; /* binary search in table */ while (max >= min) { mid = (min + max) / 2; if (keysymtab[mid].keysym < keysym) min = mid + 1; else if (keysymtab[mid].keysym > keysym) max = mid - 1; else { /* found it */ return keysymtab[mid].ucs; } } /* no matching Unicode value found */ return -1; } drawterm-20170818/gui-x11/keysym2ucs.h000066400000000000000000000003641314554504700173100ustar00rootroot00000000000000/* $XFree86: xc/programs/xterm/keysym2ucs.h,v 1.1 1999/06/12 15:37:18 dawes Exp $ */ /* * This module converts keysym values into the corresponding ISO 10646-1 * (UCS, Unicode) values. */ #include long keysym2ucs(KeySym keysym); drawterm-20170818/gui-x11/x11.c000066400000000000000000001047621314554504700156050ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include #include #include #include #include "screen.h" #define argv0 "drawterm" typedef struct Cursor Cursor; #undef long #define Font XFont #define Screen XScreen #define Display XDisplay #define Cursor XCursor #include #include #include #include #include #include #include "keysym2ucs.h" #undef Font #undef Screen #undef Display #undef Cursor #define long int /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */ #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19) enum { PMundef = ~0 /* undefined pixmap id */ }; /* * Structure pointed to by X field of Memimage */ typedef struct Xmem Xmem; struct Xmem { int pmid; /* pixmap id for screen ldepth instance */ XImage *xi; /* local image if we currenty have the data */ int dirty; Rectangle dirtyr; Rectangle r; uintptr pc; /* who wrote into xi */ }; static int xgcfillcolor; static int xgcfillcolor0; static int xgcsimplecolor0; static int xgcsimplepm0; static XDisplay* xdisplay; /* used holding draw lock */ static int xtblbit; static int plan9tox11[256]; /* Values for mapping between */ static int x11toplan9[256]; /* X11 and Plan 9 */ static GC xgcfill, xgccopy, xgcsimplesrc, xgczero, xgcreplsrc; static GC xgcfill0, xgccopy0, xgcsimplesrc0, xgczero0, xgcreplsrc0; static ulong xscreenchan; static Drawable xscreenid; static Visual *xvis; static int xdraw(Memdrawparam*); #define glenda_width 48 #define glenda_height 48 static unsigned short glenda_bits[] = { 0xffff, 0xffff, 0xffff, 0xffff, 0xffe9, 0xffff, 0x7fff, 0xffae, 0xffff, 0xffff, 0xffbe, 0xffff, 0x1fff, 0xff3f, 0xffff, 0xbfff, 0xfe6e, 0xffff, 0xbbff, 0xfcce, 0xffff, 0xffff, 0xf98c, 0xffff, 0xe5ff, 0xf31b, 0xffff, 0x87ff, 0xe617, 0xffff, 0x05ff, 0xdf37, 0xffff, 0x0fff, 0x7ffe, 0xffff, 0x1bff, 0xfffc, 0xfffa, 0x37ff, 0xfffc, 0xfffb, 0xd7ff, 0xfffc, 0xfff7, 0xcfff, 0xffff, 0xfff7, 0xcfff, 0xffff, 0xffef, 0xdfff, 0xffff, 0xffef, 0xafff, 0xffff, 0xffdf, 0xefff, 0xffff, 0xfff3, 0xdfff, 0xefff, 0xffd3, 0xdfff, 0xc7ff, 0xffdf, 0xefff, 0xefff, 0xffef, 0xcfff, 0xffff, 0xffcf, 0xdfff, 0xffff, 0xffd9, 0x9fff, 0x7fff, 0xffd0, 0xbfff, 0xffff, 0xffd7, 0x7fff, 0xbfff, 0xffd0, 0x3fff, 0x3fff, 0xffd9, 0x7fff, 0x3fff, 0xffcb, 0x3fff, 0xffff, 0xffdc, 0x3fff, 0xffff, 0xffdf, 0x3fff, 0xffff, 0xff9f, 0x3fff, 0xffff, 0xffdf, 0x8fff, 0xffff, 0xff9f, 0xa7ff, 0xffff, 0xffdf, 0xe3ff, 0xffff, 0xffcf, 0xe9ff, 0xffff, 0xffcf, 0xf1ff, 0xffff, 0xffef, 0xf3ff, 0xffff, 0xffe7, 0xf9ff, 0xffff, 0xffe7, 0x53ff, 0xffff, 0xffe1, 0x07ff, 0x7ffc, 0xffc6, 0x17ff, 0xeff0, 0xffee, 0xffff, 0xc781, 0xffe5, 0xffff, 0x8807, 0xffe0, 0xffff, 0x003f, 0xfff0, 0xffff, 0x1fff, 0xfffe }; /* * Synchronize images between X bitmaps and in-memory bitmaps. */ static void addrect(Rectangle *rp, Rectangle r) { if(rp->min.x >= rp->max.x) *rp = r; else combinerect(rp, r); } static XImage* getXdata(Memimage *m, Rectangle r) { uchar *p; int x, y; Xmem *xm; Point xdelta, delta; Point tp; xm = m->X; if(xm == nil) return nil; assert(xm != nil && xm->xi != nil); if(xm->dirty == 0) return xm->xi; r = xm->dirtyr; if(Dx(r)==0 || Dy(r)==0) return xm->xi; delta = subpt(r.min, m->r.min); tp = xm->r.min; /* avoid unaligned access on digital unix */ xdelta = subpt(r.min, tp); XGetSubImage(xdisplay, xm->pmid, delta.x, delta.y, Dx(r), Dy(r), AllPlanes, ZPixmap, xm->xi, xdelta.x, xdelta.y); if(xtblbit && m->chan == CMAP8) for(y=r.min.y; ydirty = 0; xm->dirtyr = Rect(0,0,0,0); return xm->xi; } static void putXdata(Memimage *m, Rectangle r) { Xmem *xm; XImage *xi; GC g; Point xdelta, delta; Point tp; int x, y; uchar *p; xm = m->X; if(xm == nil) return; assert(xm != nil); assert(xm->xi != nil); xi = xm->xi; g = (m->chan == GREY1) ? xgccopy0 : xgccopy; delta = subpt(r.min, m->r.min); tp = xm->r.min; /* avoid unaligned access on digital unix */ xdelta = subpt(r.min, tp); if(xtblbit && m->chan == CMAP8) for(y=r.min.y; ypmid, g, xi, xdelta.x, xdelta.y, delta.x, delta.y, Dx(r), Dy(r)); if(xtblbit && m->chan == CMAP8) for(y=r.min.y; yX) != nil){ xm->dirty = 1; addrect(&xm->dirtyr, r); } } Memimage* xallocmemimage(Rectangle r, ulong chan, int pmid) { Memimage *m; Xmem *xm; XImage *xi; int offset; int d; m = _allocmemimage(r, chan); if(m == nil) return nil; if(chan != GREY1 && chan != xscreenchan) return m; d = m->depth; xm = mallocz(sizeof(Xmem), 1); if(pmid != PMundef) xm->pmid = pmid; else xm->pmid = XCreatePixmap(xdisplay, xscreenid, Dx(r), Dy(r), (d==32) ? 24 : d); if(m->depth == 24) offset = r.min.x&(4-1); else offset = r.min.x&(31/m->depth); r.min.x -= offset; assert(wordsperline(r, m->depth) <= m->width); xi = XCreateImage(xdisplay, xvis, m->depth==32?24:m->depth, ZPixmap, 0, (char*)m->data->bdata, Dx(r), Dy(r), 32, m->width*sizeof(ulong)); if(xi == nil){ _freememimage(m); return nil; } xm->xi = xi; xm->pc = getcallerpc(&r); xm->r = r; /* * Set the parameters of the XImage so its memory looks exactly like a * Memimage, so we can call _memimagedraw on the same data. All frame * buffers we've seen, and Plan 9's graphics code, require big-endian * bits within bytes, but little endian byte order within pixels. */ xi->bitmap_unit = m->depth < 8 || m->depth == 24 ? 8 : m->depth; xi->byte_order = LSBFirst; xi->bitmap_bit_order = MSBFirst; xi->bitmap_pad = 32; xm->r = Rect(0,0,0,0); XInitImage(xi); XFlush(xdisplay); m->X = xm; return m; } void xfillcolor(Memimage *m, Rectangle r, ulong v) { GC gc; Xmem *dxm; dxm = m->X; assert(dxm != nil); r = rectsubpt(r, m->r.min); if(m->chan == GREY1){ gc = xgcfill0; if(xgcfillcolor0 != v){ XSetForeground(xdisplay, gc, v); xgcfillcolor0 = v; } }else{ if(m->chan == CMAP8 && xtblbit) v = plan9tox11[v]; gc = xgcfill; if(xgcfillcolor != v){ XSetForeground(xdisplay, gc, v); xgcfillcolor = v; } } XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, Dx(r), Dy(r)); } /* * Replacements for libmemdraw routines. * (They've been underscored.) */ Memimage* allocmemimage(Rectangle r, ulong chan) { return xallocmemimage(r, chan, PMundef); } void freememimage(Memimage *m) { Xmem *xm; if(m == nil) return; if(m->data->ref == 1){ if((xm = m->X) != nil){ if(xm->xi){ xm->xi->data = nil; XFree(xm->xi); } XFreePixmap(xdisplay, xm->pmid); free(xm); m->X = nil; } } _freememimage(m); } void memfillcolor(Memimage *m, ulong val) { _memfillcolor(m, val); if(m->X){ if((val & 0xFF) == 0xFF) xfillcolor(m, m->r, _rgbatoimg(m, val)); else putXdata(m, m->r); } } int loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) { int n; n = _loadmemimage(i, r, data, ndata); if(n > 0 && i->X) putXdata(i, r); return n; } int cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) { int n; n = _cloadmemimage(i, r, data, ndata); if(n > 0 && i->X) putXdata(i, r); return n; } ulong pixelbits(Memimage *m, Point p) { if(m->X) getXdata(m, Rect(p.x, p.y, p.x+1, p.y+1)); return _pixelbits(m, p); } void memimageinit(void) { static int didinit = 0; if(didinit) return; didinit = 1; _memimageinit(); xfillcolor(memblack, memblack->r, 0); xfillcolor(memwhite, memwhite->r, 1); } void memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op) { Memdrawparam *par; if((par = _memimagedrawsetup(dst, r, src, sp, mask, mp, op)) == nil) return; _memimagedraw(par); if(!xdraw(par)) putXdata(dst, par->r); } static int xdraw(Memdrawparam *par) { int dy, dx; unsigned m; Memimage *src, *dst, *mask; Xmem *dxm, *sxm, *mxm; GC gc; Rectangle r, sr, mr; ulong sdval; dx = Dx(par->r); dy = Dy(par->r); src = par->src; dst = par->dst; mask = par->mask; r = par->r; sr = par->sr; mr = par->mr; sdval = par->sdval; /* * drawterm was distributed for years with * "return 0;" right here. * maybe we should give up on all this? */ if((dxm = dst->X) == nil) return 0; /* * If we have an opaque mask and source is one opaque pixel we can convert to the * destination format and just XFillRectangle. */ m = Simplesrc|Simplemask|Fullmask; if((par->state&m)==m){ xfillcolor(dst, r, sdval); dirtyXdata(dst, par->r); return 1; } /* * If no source alpha, an opaque mask, we can just copy the * source onto the destination. If the channels are the same and * the source is not replicated, XCopyArea suffices. */ m = Simplemask|Fullmask; if((par->state&(m|Replsrc))==m && src->chan == dst->chan && src->X){ sxm = src->X; r = rectsubpt(r, dst->r.min); sr = rectsubpt(sr, src->r.min); if(dst->chan == GREY1) gc = xgccopy0; else gc = xgccopy; XCopyArea(xdisplay, sxm->pmid, dxm->pmid, gc, sr.min.x, sr.min.y, dx, dy, r.min.x, r.min.y); dirtyXdata(dst, par->r); return 1; } /* * If no source alpha, a 1-bit mask, and a simple source * we can just copy through the mask onto the destination. */ if(dst->X && mask->X && !(mask->flags&Frepl) && mask->chan == GREY1 && (par->state&Simplesrc)){ Point p; mxm = mask->X; r = rectsubpt(r, dst->r.min); mr = rectsubpt(mr, mask->r.min); p = subpt(r.min, mr.min); if(dst->chan == GREY1){ gc = xgcsimplesrc0; if(xgcsimplecolor0 != sdval){ XSetForeground(xdisplay, gc, sdval); xgcsimplecolor0 = sdval; } if(xgcsimplepm0 != mxm->pmid){ XSetStipple(xdisplay, gc, mxm->pmid); xgcsimplepm0 = mxm->pmid; } }else{ /* somehow this doesn't work on rob's mac gc = xgcsimplesrc; if(dst->chan == CMAP8 && xtblbit) sdval = plan9tox11[sdval]; if(xgcsimplecolor != sdval){ XSetForeground(xdisplay, gc, sdval); xgcsimplecolor = sdval; } if(xgcsimplepm != mxm->pmid){ XSetStipple(xdisplay, gc, mxm->pmid); xgcsimplepm = mxm->pmid; } */ return 0; } XSetTSOrigin(xdisplay, gc, p.x, p.y); XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, dx, dy); dirtyXdata(dst, par->r); return 1; } return 0; } /* * X11 window management and kernel hooks. * Oh, how I loathe this code! */ static XColor map[256]; /* Plan 9 colormap array */ static XColor map7[128]; /* Plan 9 colormap array */ static uchar map7to8[128][2]; static Colormap xcmap; /* Default shared colormap */ extern int mousequeue; /* for copy/paste, lifted from plan9ports */ static Atom clipboard; static Atom utf8string; static Atom targets; static Atom text; static Atom compoundtext; static Drawable xdrawable; static void xexpose(XEvent*); static void xmouse(XEvent*); static void xkeyboard(XEvent*); static void xmapping(XEvent*); static void xdestroy(XEvent*); static void xselect(XEvent*, XDisplay*); static void xproc(void*); static Memimage* xinitscreen(void); static void initmap(Window); static GC creategc(Drawable); static void graphicscmap(XColor*); static int xscreendepth; static XDisplay* xkmcon; /* used only in xproc */ static XDisplay* xsnarfcon; /* used holding clip.lk */ static ulong xblack; static ulong xwhite; static int putsnarf, assertsnarf; Memimage *gscreen; Screeninfo screen; void flushmemscreen(Rectangle r) { assert(!drawcanqlock()); if(r.min.x >= r.max.x || r.min.y >= r.max.y) return; XCopyArea(xdisplay, xscreenid, xdrawable, xgccopy, r.min.x, r.min.y, Dx(r), Dy(r), r.min.x, r.min.y); XFlush(xdisplay); } void screeninit(void) { _memmkcmap(); gscreen = xinitscreen(); kproc("xscreen", xproc, nil); memimageinit(); terminit(); drawqlock(); flushmemscreen(gscreen->r); drawqunlock(); } uchar* attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen, void **X) { *r = gscreen->r; *chan = gscreen->chan; *depth = gscreen->depth; *width = gscreen->width; *X = gscreen->X; *softscreen = 1; return gscreen->data->bdata; } static int revbyte(int b) { int r; r = 0; r |= (b&0x01) << 7; r |= (b&0x02) << 5; r |= (b&0x04) << 3; r |= (b&0x08) << 1; r |= (b&0x10) >> 1; r |= (b&0x20) >> 3; r |= (b&0x40) >> 5; r |= (b&0x80) >> 7; return r; } void mouseset(Point xy) { drawqlock(); XWarpPointer(xdisplay, None, xdrawable, 0, 0, 0, 0, xy.x, xy.y); XFlush(xdisplay); drawqunlock(); } static XCursor xcursor; void setcursor(void) { XCursor xc; XColor fg, bg; Pixmap xsrc, xmask; int i; uchar src[2*16], mask[2*16]; for(i=0; i<2*16; i++){ src[i] = revbyte(cursor.set[i]); mask[i] = revbyte(cursor.set[i] | cursor.clr[i]); } drawqlock(); fg = map[0]; bg = map[255]; xsrc = XCreateBitmapFromData(xdisplay, xdrawable, (char*)src, 16, 16); xmask = XCreateBitmapFromData(xdisplay, xdrawable, (char*)mask, 16, 16); xc = XCreatePixmapCursor(xdisplay, xsrc, xmask, &fg, &bg, -cursor.offset.x, -cursor.offset.y); if(xc != 0) { XDefineCursor(xdisplay, xdrawable, xc); if(xcursor != 0) XFreeCursor(xdisplay, xcursor); xcursor = xc; } XFreePixmap(xdisplay, xsrc); XFreePixmap(xdisplay, xmask); XFlush(xdisplay); drawqunlock(); } void cursorarrow(void) { drawqlock(); if(xcursor != 0){ XFreeCursor(xdisplay, xcursor); xcursor = 0; } XUndefineCursor(xdisplay, xdrawable); XFlush(xdisplay); drawqunlock(); } static void xproc(void *arg) { ulong mask; XEvent event; mask = KeyPressMask| ButtonPressMask| ButtonReleaseMask| PointerMotionMask| Button1MotionMask| Button2MotionMask| Button3MotionMask| Button4MotionMask| Button5MotionMask| ExposureMask| StructureNotifyMask; XSelectInput(xkmcon, xdrawable, mask); for(;;) { //XWindowEvent(xkmcon, xdrawable, mask, &event); XNextEvent(xkmcon, &event); xselect(&event, xkmcon); xkeyboard(&event); xmouse(&event); xexpose(&event); xmapping(&event); xdestroy(&event); } } static int shutup(XDisplay *d, XErrorEvent *e) { char buf[200]; iprint("X error: error code=%d, request_code=%d, minor=%d\n", e->error_code, e->request_code, e->minor_code); XGetErrorText(d, e->error_code, buf, sizeof(buf)); iprint("%s\n", buf); USED(d); USED(e); return 0; } static int panicshutup(XDisplay *d) { panic("x error"); return -1; } static Memimage* xinitscreen(void) { Memimage *gscreen; int i, xsize, ysize, pmid; char *argv[2]; char *disp_val; Window rootwin; Rectangle r; XWMHints hints; XScreen *screen; XVisualInfo xvi; int rootscreennum; XTextProperty name; XClassHint classhints; XSizeHints normalhints; XSetWindowAttributes attrs; XPixmapFormatValues *pfmt; int n; Pixmap icon_pixmap; xscreenid = 0; xdrawable = 0; xdisplay = XOpenDisplay(NULL); if(xdisplay == 0){ iprint("xinitscreen: XOpenDisplay: %r [DISPLAY=%s]\n", getenv("DISPLAY")); exit(0); } XSetErrorHandler(shutup); XSetIOErrorHandler(panicshutup); rootscreennum = DefaultScreen(xdisplay); rootwin = DefaultRootWindow(xdisplay); xscreendepth = DefaultDepth(xdisplay, rootscreennum); if(XMatchVisualInfo(xdisplay, rootscreennum, 16, TrueColor, &xvi) || XMatchVisualInfo(xdisplay, rootscreennum, 16, DirectColor, &xvi)){ xvis = xvi.visual; xscreendepth = 16; xtblbit = 1; } else if(XMatchVisualInfo(xdisplay, rootscreennum, 24, TrueColor, &xvi) || XMatchVisualInfo(xdisplay, rootscreennum, 24, DirectColor, &xvi)){ xvis = xvi.visual; xscreendepth = 24; xtblbit = 1; } else if(XMatchVisualInfo(xdisplay, rootscreennum, 8, PseudoColor, &xvi) || XMatchVisualInfo(xdisplay, rootscreennum, 8, StaticColor, &xvi)){ if(xscreendepth > 8) panic("drawterm: can't deal with colormapped depth %d screens\n", xscreendepth); xvis = xvi.visual; xscreendepth = 8; } else{ if(xscreendepth != 8) panic("drawterm: can't deal with depth %d screens\n", xscreendepth); xvis = DefaultVisual(xdisplay, rootscreennum); } /* * xscreendepth is only the number of significant pixel bits, * not the total. We need to walk the display list to find * how many actual bits are being used per pixel. */ xscreenchan = 0; /* not a valid channel */ pfmt = XListPixmapFormats(xdisplay, &n); for(i=0; iclass != StaticColor){ graphicscmap(map); initmap(rootwin); } r.min = ZP; r.max.x = WidthOfScreen(screen); r.max.y = HeightOfScreen(screen); xsize = Dx(r)*3/4; ysize = Dy(r)*3/4; attrs.colormap = xcmap; attrs.background_pixel = 0; attrs.border_pixel = 0; /* attrs.override_redirect = 1;*/ /* WM leave me alone! |CWOverrideRedirect */ xdrawable = XCreateWindow(xdisplay, rootwin, 0, 0, xsize, ysize, 0, xscreendepth, InputOutput, xvis, CWBackPixel|CWBorderPixel|CWColormap, &attrs); /* load the given bitmap data and create an X pixmap containing it. */ icon_pixmap = XCreateBitmapFromData(xdisplay, rootwin, (char *)glenda_bits, glenda_width, glenda_height); /* * set up property as required by ICCCM */ name.value = (uchar*)"drawterm"; name.encoding = XA_STRING; name.format = 8; name.nitems = strlen((char*)name.value); normalhints.flags = USSize|PMaxSize; normalhints.max_width = Dx(r); normalhints.max_height = Dy(r); normalhints.width = xsize; normalhints.height = ysize; hints.flags = IconPixmapHint |InputHint|StateHint; hints.input = 1; hints.initial_state = NormalState; hints.icon_pixmap = icon_pixmap; classhints.res_name = "drawterm"; classhints.res_class = "Drawterm"; argv[0] = "drawterm"; argv[1] = nil; XSetWMProperties(xdisplay, xdrawable, &name, /* XA_WM_NAME property for ICCCM */ &name, /* XA_WM_ICON_NAME */ argv, /* XA_WM_COMMAND */ 1, /* argc */ &normalhints, /* XA_WM_NORMAL_HINTS */ &hints, /* XA_WM_HINTS */ &classhints); /* XA_WM_CLASS */ XFlush(xdisplay); /* * put the window on the screen */ XMapWindow(xdisplay, xdrawable); XFlush(xdisplay); xscreenid = XCreatePixmap(xdisplay, xdrawable, Dx(r), Dy(r), xscreendepth); gscreen = xallocmemimage(r, xscreenchan, xscreenid); xgcfill = creategc(xscreenid); XSetFillStyle(xdisplay, xgcfill, FillSolid); xgccopy = creategc(xscreenid); xgcsimplesrc = creategc(xscreenid); XSetFillStyle(xdisplay, xgcsimplesrc, FillStippled); xgczero = creategc(xscreenid); xgcreplsrc = creategc(xscreenid); XSetFillStyle(xdisplay, xgcreplsrc, FillTiled); pmid = XCreatePixmap(xdisplay, xdrawable, 1, 1, 1); xgcfill0 = creategc(pmid); XSetForeground(xdisplay, xgcfill0, 0); XSetFillStyle(xdisplay, xgcfill0, FillSolid); xgccopy0 = creategc(pmid); xgcsimplesrc0 = creategc(pmid); XSetFillStyle(xdisplay, xgcsimplesrc0, FillStippled); xgczero0 = creategc(pmid); xgcreplsrc0 = creategc(pmid); XSetFillStyle(xdisplay, xgcreplsrc0, FillTiled); XFreePixmap(xdisplay, pmid); XSetForeground(xdisplay, xgccopy, plan9tox11[0]); XFillRectangle(xdisplay, xscreenid, xgccopy, 0, 0, xsize, ysize); xkmcon = XOpenDisplay(NULL); if(xkmcon == 0){ disp_val = getenv("DISPLAY"); if(disp_val == 0) disp_val = "not set"; iprint("drawterm: open %r, DISPLAY is %s\n", disp_val); exit(0); } xsnarfcon = XOpenDisplay(NULL); if(xsnarfcon == 0){ disp_val = getenv("DISPLAY"); if(disp_val == 0) disp_val = "not set"; iprint("drawterm: open %r, DISPLAY is %s\n", disp_val); exit(0); } clipboard = XInternAtom(xkmcon, "CLIPBOARD", False); utf8string = XInternAtom(xkmcon, "UTF8_STRING", False); targets = XInternAtom(xkmcon, "TARGETS", False); text = XInternAtom(xkmcon, "TEXT", False); compoundtext = XInternAtom(xkmcon, "COMPOUND_TEXT", False); xblack = screen->black_pixel; xwhite = screen->white_pixel; return gscreen; } static void graphicscmap(XColor *map) { int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7; for(r=0; r!=4; r++) { for(g = 0; g != 4; g++) { for(b = 0; b!=4; b++) { for(v = 0; v!=4; v++) { den=r; if(g > den) den=g; if(b > den) den=b; /* divide check -- pick grey shades */ if(den==0) cr=cg=cb=v*17; else { num=17*(4*den+v); cr=r*num/den; cg=g*num/den; cb=b*num/den; } idx = r*64 + v*16 + ((g*4 + b + v - r) & 15); map[idx].red = cr*0x0101; map[idx].green = cg*0x0101; map[idx].blue = cb*0x0101; map[idx].pixel = idx; map[idx].flags = DoRed|DoGreen|DoBlue; v7 = v >> 1; idx7 = r*32 + v7*16 + g*4 + b; if((v & 1) == v7){ map7to8[idx7][0] = idx; if(den == 0) { /* divide check -- pick grey shades */ cr = ((255.0/7.0)*v7)+0.5; cg = cr; cb = cr; } else { num=17*15*(4*den+v7*2)/14; cr=r*num/den; cg=g*num/den; cb=b*num/den; } map7[idx7].red = cr*0x0101; map7[idx7].green = cg*0x0101; map7[idx7].blue = cb*0x0101; map7[idx7].pixel = idx7; map7[idx7].flags = DoRed|DoGreen|DoBlue; } else map7to8[idx7][1] = idx; } } } } } /* * Initialize and install the drawterm colormap as a private colormap for this * application. Drawterm gets the best colors here when it has the cursor focus. */ static void initmap(Window w) { XColor c; int i; ulong p, pp; char buf[30]; if(xscreendepth <= 1) return; if(xscreendepth >= 24) { /* The pixel value returned from XGetPixel needs to * be converted to RGB so we can call rgb2cmap() * to translate between 24 bit X and our color. Unfortunately, * the return value appears to be display server endian * dependant. Therefore, we run some heuristics to later * determine how to mask the int value correctly. * Yeah, I know we can look at xvis->byte_order but * some displays say MSB even though they run on LSB. * Besides, this is more anal. */ if(xscreendepth != DefaultDepth(xdisplay, DefaultScreen(xdisplay))) xcmap = XCreateColormap(xdisplay, w, xvis, AllocNone); c = map[19]; /* find out index into colormap for our RGB */ if(!XAllocColor(xdisplay, xcmap, &c)) panic("drawterm: screen-x11 can't alloc color"); p = c.pixel; pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff); if(pp!=map[19].pixel) { /* check if endian is other way */ pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff); if(pp!=map[19].pixel) panic("cannot detect x server byte order"); switch(xscreenchan){ case RGB24: xscreenchan = BGR24; break; case XRGB32: xscreenchan = XBGR32; break; default: panic("don't know how to byteswap channel %s", chantostr(buf, xscreenchan)); break; } } } else if(xvis->class == TrueColor || xvis->class == DirectColor) { } else if(xvis->class == PseudoColor) { if(xtblbit == 0){ xcmap = XCreateColormap(xdisplay, w, xvis, AllocAll); XStoreColors(xdisplay, xcmap, map, 256); for(i = 0; i < 256; i++) { plan9tox11[i] = i; x11toplan9[i] = i; } } else { for(i = 0; i < 128; i++) { c = map7[i]; if(!XAllocColor(xdisplay, xcmap, &c)) { iprint("drawterm: can't alloc colors in default map, don't use -7\n"); exit(0); } plan9tox11[map7to8[i][0]] = c.pixel; plan9tox11[map7to8[i][1]] = c.pixel; x11toplan9[c.pixel] = map7to8[i][0]; } } } else panic("drawterm: unsupported visual class %d\n", xvis->class); } static void xdestroy(XEvent *e) { XDestroyWindowEvent *xe; if(e->type != DestroyNotify) return; xe = (XDestroyWindowEvent*)e; if(xe->window == xdrawable) exit(0); } static void xmapping(XEvent *e) { XMappingEvent *xe; if(e->type != MappingNotify) return; xe = (XMappingEvent*)e; USED(xe); } /* * Disable generation of GraphicsExpose/NoExpose events in the GC. */ static GC creategc(Drawable d) { XGCValues gcv; gcv.function = GXcopy; gcv.graphics_exposures = False; return XCreateGC(xdisplay, d, GCFunction|GCGraphicsExposures, &gcv); } static void xexpose(XEvent *e) { Rectangle r; XExposeEvent *xe; if(e->type != Expose) return; xe = (XExposeEvent*)e; r.min.x = xe->x; r.min.y = xe->y; r.max.x = xe->x + xe->width; r.max.y = xe->y + xe->height; drawflushr(r); } static void xkeyboard(XEvent *e) { KeySym k; /* * I tried using XtGetActionKeysym, but it didn't seem to * do case conversion properly * (at least, with Xterminal servers and R4 intrinsics) */ if(e->xany.type != KeyPress) return; XLookupString((XKeyEvent*)e, NULL, 0, &k, NULL); if(k == XK_Multi_key || k == NoSymbol) return; if(k&0xFF00){ switch(k){ case XK_BackSpace: case XK_Tab: case XK_Escape: case XK_Delete: case XK_KP_0: case XK_KP_1: case XK_KP_2: case XK_KP_3: case XK_KP_4: case XK_KP_5: case XK_KP_6: case XK_KP_7: case XK_KP_8: case XK_KP_9: case XK_KP_Divide: case XK_KP_Multiply: case XK_KP_Subtract: case XK_KP_Add: case XK_KP_Decimal: k &= 0x7F; break; case XK_Linefeed: k = '\r'; break; case XK_KP_Space: k = ' '; break; case XK_Home: case XK_KP_Home: k = Khome; break; case XK_Left: case XK_KP_Left: k = Kleft; break; case XK_Up: case XK_KP_Up: k = Kup; break; case XK_Down: case XK_KP_Down: k = Kdown; break; case XK_Right: case XK_KP_Right: k = Kright; break; case XK_Page_Down: case XK_KP_Page_Down: k = Kpgdown; break; case XK_End: case XK_KP_End: k = Kend; break; case XK_Page_Up: case XK_KP_Page_Up: k = Kpgup; break; case XK_Insert: case XK_KP_Insert: k = Kins; break; case XK_KP_Enter: case XK_Return: k = '\n'; break; case XK_Alt_L: case XK_Alt_R: k = Kalt; break; case XK_F1: case XK_F2: case XK_F3: case XK_F4: case XK_F5: case XK_F6: case XK_F7: case XK_F8: case XK_F9: case XK_F10: case XK_F11: case XK_F12: k = KF|(k - XK_F1 + 1); break; case XK_Shift_L: case XK_Shift_R: case XK_Control_L: case XK_Control_R: case XK_Caps_Lock: case XK_Shift_Lock: case XK_Meta_L: case XK_Meta_R: case XK_Super_L: case XK_Super_R: case XK_Hyper_L: case XK_Hyper_R: return; default: /* not ISO-1 or tty control */ if(k>0xff){ k = keysym2ucs(k); /* supplied by X */ if(k == -1) return; } break; } } /* Compensate for servers that call a minus a hyphen */ if(k == XK_hyphen) k = XK_minus; /* Do control mapping ourselves if translator doesn't */ if(e->xkey.state&ControlMask && k != Kalt) k &= 0x9f; if(k == NoSymbol) { return; } kbdputc(kbdq, k); } static void xmouse(XEvent *e) { Mousestate ms; int i, s; XButtonEvent *be; XMotionEvent *me; if(putsnarf != assertsnarf){ assertsnarf = putsnarf; XSetSelectionOwner(xkmcon, XA_PRIMARY, xdrawable, CurrentTime); if(clipboard != None) XSetSelectionOwner(xkmcon, clipboard, xdrawable, CurrentTime); XFlush(xkmcon); } switch(e->type){ case ButtonPress: be = (XButtonEvent *)e; /* * Fake message, just sent to make us announce snarf. * Apparently state and button are 16 and 8 bits on * the wire, since they are truncated by the time they * get to us. */ if(be->send_event && (~be->state&0xFFFF)==0 && (~be->button&0xFF)==0) return; ms.xy.x = be->x; ms.xy.y = be->y; s = be->state; ms.msec = be->time; switch(be->button){ case 1: s |= Button1Mask; break; case 2: s |= Button2Mask; break; case 3: s |= Button3Mask; break; case 4: s |= Button4Mask; break; case 5: s |= Button5Mask; break; } break; case ButtonRelease: be = (XButtonEvent *)e; ms.xy.x = be->x; ms.xy.y = be->y; ms.msec = be->time; s = be->state; switch(be->button){ case 1: s &= ~Button1Mask; break; case 2: s &= ~Button2Mask; break; case 3: s &= ~Button3Mask; break; case 4: s &= ~Button4Mask; break; case 5: s &= ~Button5Mask; break; } break; case MotionNotify: me = (XMotionEvent *)e; s = me->state; ms.xy.x = me->x; ms.xy.y = me->y; ms.msec = me->time; break; default: return; } ms.buttons = 0; if(s & Button1Mask) ms.buttons |= 1; if(s & Button2Mask) ms.buttons |= 2; if(s & Button3Mask) ms.buttons |= 4; if(s & Button4Mask) ms.buttons |= 8; if(s & Button5Mask) ms.buttons |= 16; lock(&mouse.lk); i = mouse.wi; if(mousequeue) { if(i == mouse.ri || mouse.lastb != ms.buttons || mouse.trans) { mouse.wi = (i+1)%Mousequeue; if(mouse.wi == mouse.ri) mouse.ri = (mouse.ri+1)%Mousequeue; mouse.trans = mouse.lastb != ms.buttons; } else { i = (i-1+Mousequeue)%Mousequeue; } } else { mouse.wi = (i+1)%Mousequeue; mouse.ri = i; } mouse.queue[i] = ms; mouse.lastb = ms.buttons; unlock(&mouse.lk); wakeup(&mouse.r); } void getcolor(ulong i, ulong *r, ulong *g, ulong *b) { ulong v; v = cmap2rgb(i); *r = (v>>16)&0xFF; *g = (v>>8)&0xFF; *b = v&0xFF; } void setcolor(ulong i, ulong r, ulong g, ulong b) { /* no-op */ } int atlocalconsole(void) { char *p, *q; char buf[128]; p = getenv("DRAWTERM_ATLOCALCONSOLE"); if(p && atoi(p) == 1) return 1; p = getenv("DISPLAY"); if(p == nil) return 0; /* extract host part */ q = strchr(p, ':'); if(q == nil) return 0; *q = 0; if(strcmp(p, "") == 0) return 1; /* try to match against system name (i.e. for ssh) */ if(gethostname(buf, sizeof buf) == 0){ if(strcmp(p, buf) == 0) return 1; if(strncmp(p, buf, strlen(p)) == 0 && buf[strlen(p)]=='.') return 1; } return 0; } /* * Cut and paste. Just couldn't stand to make this simple... */ typedef struct Clip Clip; struct Clip { char buf[SnarfSize]; QLock lk; }; Clip clip; #undef long /* sic */ #undef ulong static char* _xgetsnarf(XDisplay *xd) { uchar *data, *xdata; Atom clipboard, type, prop; unsigned long lastlen; unsigned long dummy, len; int fmt, i; Window w; qlock(&clip.lk); /* * Have we snarfed recently and the X server hasn't caught up? */ if(putsnarf != assertsnarf) goto mine; /* * Is there a primary selection (highlighted text in an xterm)? */ clipboard = XA_PRIMARY; w = XGetSelectionOwner(xd, XA_PRIMARY); if(w == xdrawable){ mine: data = (uchar*)strdup(clip.buf); goto out; } /* * If not, is there a clipboard selection? */ if(w == None && clipboard != None){ w = XGetSelectionOwner(xd, clipboard); if(w == xdrawable) goto mine; } /* * If not, give up. */ if(w == None){ data = nil; goto out; } /* * We should be waiting for SelectionNotify here, but it might never * come, and we have no way to time out. Instead, we will clear * local property #1, request our buddy to fill it in for us, and poll * until he's done or we get tired of waiting. * * We should try to go for utf8string instead of XA_STRING, * but that would add to the polling. */ prop = 1; XChangeProperty(xd, xdrawable, prop, XA_STRING, 8, PropModeReplace, (uchar*)"", 0); XConvertSelection(xd, clipboard, XA_STRING, prop, xdrawable, CurrentTime); XFlush(xd); lastlen = 0; for(i=0; i<10 || (lastlen!=0 && i<30); i++){ usleep(100*1000); XGetWindowProperty(xd, xdrawable, prop, 0, 0, 0, AnyPropertyType, &type, &fmt, &dummy, &len, &data); if(lastlen == len && len > 0) break; lastlen = len; } if(i == 10){ data = nil; goto out; } /* get the property */ data = nil; XGetWindowProperty(xd, xdrawable, prop, 0, SnarfSize/sizeof(unsigned long), 0, AnyPropertyType, &type, &fmt, &len, &dummy, &xdata); if((type != XA_STRING && type != utf8string) || len == 0){ if(xdata) XFree(xdata); data = nil; }else{ if(xdata){ data = (uchar*)strdup((char*)xdata); XFree(xdata); }else data = nil; } out: qunlock(&clip.lk); return (char*)data; } static void _xputsnarf(XDisplay *xd, char *data) { XButtonEvent e; if(strlen(data) >= SnarfSize) return; qlock(&clip.lk); strcpy(clip.buf, data); /* leave note for mouse proc to assert selection ownership */ putsnarf++; /* send mouse a fake event so snarf is announced */ memset(&e, 0, sizeof e); e.type = ButtonPress; e.window = xdrawable; e.state = ~0; e.button = ~0; XSendEvent(xd, xdrawable, True, ButtonPressMask, (XEvent*)&e); XFlush(xd); qunlock(&clip.lk); } static void xselect(XEvent *e, XDisplay *xd) { char *name; XEvent r; XSelectionRequestEvent *xe; Atom a[4]; if(e->xany.type != SelectionRequest) return; memset(&r, 0, sizeof r); xe = (XSelectionRequestEvent*)e; if(0) iprint("xselect target=%d requestor=%d property=%d selection=%d\n", xe->target, xe->requestor, xe->property, xe->selection); r.xselection.property = xe->property; if(xe->target == targets){ a[0] = XA_STRING; a[1] = utf8string; a[2] = text; a[3] = compoundtext; XChangeProperty(xd, xe->requestor, xe->property, XA_ATOM, 32, PropModeReplace, (uchar*)a, sizeof a); }else if(xe->target == XA_STRING || xe->target == utf8string || xe->target == text || xe->target == compoundtext){ text: /* if the target is STRING we're supposed to reply with Latin1 XXX */ qlock(&clip.lk); XChangeProperty(xd, xe->requestor, xe->property, xe->target, 8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf)); qunlock(&clip.lk); }else{ name = XGetAtomName(xd, xe->target); if(name == nil) iprint("XGetAtomName %d failed\n", xe->target); if(name){ if(strcmp(name, "TIMESTAMP") == 0){ /* nothing */ }else if(strncmp(name, "image/", 6) == 0){ /* nothing */ }else if(strcmp(name, "text/html") == 0){ /* nothing */ }else if(strcmp(name, "text/plain") == 0 || strcmp(name, "text/plain;charset=UTF-8") == 0){ goto text; }else iprint("%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target); } r.xselection.property = None; } r.xselection.display = xe->display; /* r.xselection.property filled above */ r.xselection.target = xe->target; r.xselection.type = SelectionNotify; r.xselection.requestor = xe->requestor; r.xselection.time = xe->time; r.xselection.send_event = True; r.xselection.selection = xe->selection; XSendEvent(xd, xe->requestor, False, 0, &r); XFlush(xd); } char* clipread(void) { return _xgetsnarf(xsnarfcon); } int clipwrite(char *buf) { _xputsnarf(xsnarfcon, buf); return 0; } drawterm-20170818/include/000077500000000000000000000000001314554504700152465ustar00rootroot00000000000000drawterm-20170818/include/9windows.h000066400000000000000000000006761314554504700172130ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include /* disable various silly warnings */ #ifdef MSVC #pragma warning( disable : 4245 4305 4244 4102 4761 4090 4028 4024) #endif typedef __int64 p9_vlong; typedef unsigned __int64 p9_uvlong; typedef unsigned uintptr; drawterm-20170818/include/auth.h000066400000000000000000000067221314554504700163670ustar00rootroot00000000000000#ifdef PLAN9 #pragma src "/sys/src/libauth" #pragma lib "libauth.a" #endif /* * Interface for typical callers. */ typedef struct AuthInfo AuthInfo; typedef struct Chalstate Chalstate; typedef struct Chapreply Chapreply; typedef struct MSchapreply MSchapreply; typedef struct UserPasswd UserPasswd; typedef struct AuthRpc AuthRpc; enum { MAXCHLEN= 256, /* max challenge length */ AMAXNAMELEN= 256, /* maximum name length */ MD5LEN= 16, ARok = 0, /* rpc return values */ ARdone, ARerror, ARneedkey, ARbadkey, ARwritenext, ARtoosmall, ARtoobig, ARrpcfailure, ARphase, AuthRpcMax = 4096, }; struct AuthRpc { int afd; char ibuf[AuthRpcMax]; char obuf[AuthRpcMax]; char *arg; uint narg; }; struct AuthInfo { char *cuid; /* caller id */ char *suid; /* server id */ char *cap; /* capability (only valid on server side) */ int nsecret; /* length of secret */ uchar *secret; /* secret */ }; struct Chalstate { char *user; char chal[MAXCHLEN]; int nchal; void *resp; int nresp; /* for implementation only */ int afd; /* to factotum */ AuthRpc *rpc; /* to factotum */ char userbuf[AMAXNAMELEN]; /* temp space if needed */ int userinchal; /* user was sent to obtain challenge */ }; struct Chapreply /* for protocol "chap" */ { uchar id; char resp[MD5LEN]; }; struct MSchapreply /* for protocol "mschap" */ { char LMresp[24]; /* Lan Manager response */ char NTresp[24]; /* NT response */ }; struct UserPasswd { char *user; char *passwd; }; extern int newns(char*, char*); extern int addns(char*, char*); extern int noworld(char*); extern int amount(int, char*, int, char*); /* these two may get generalized away -rsc */ extern int login(char*, char*, char*); extern int httpauth(char*, char*); typedef struct Attr Attr; typedef struct String String; enum { AttrNameval, /* name=val -- when matching, must have name=val */ AttrQuery, /* name? -- when matching, must be present */ AttrDefault, /* name:=val -- when matching, if present must match INTERNAL */ }; struct Attr { int type; Attr *next; char *name; char *val; }; typedef int AuthGetkey(char*); int _attrfmt(Fmt*); Attr *_copyattr(Attr*); Attr *_delattr(Attr*, char*); Attr *_findattr(Attr*, char*); void _freeattr(Attr*); Attr *_mkattr(int, char*, char*, Attr*); Attr *_parseattr(char*); char *_strfindattr(Attr*, char*); #ifdef VARARGCK #pragma varargck type "A" Attr* #endif extern AuthInfo* fauth_proxy(int, AuthRpc *rpc, AuthGetkey *getkey, char *params); extern AuthInfo* auth_proxy(int fd, AuthGetkey *getkey, char *fmt, ...); extern int auth_getkey(char*); extern int (*amount_getkey)(char*); extern void auth_freeAI(AuthInfo *ai); extern int auth_chuid(AuthInfo *ai, char *ns); extern Chalstate *auth_challenge(char*, ...); extern AuthInfo* auth_response(Chalstate*); extern int auth_respond(void*, uint, char*, uint, void*, uint, AuthGetkey *getkey, char*, ...); extern void auth_freechal(Chalstate*); extern AuthInfo* auth_userpasswd(char *user, char *passwd); extern UserPasswd* auth_getuserpasswd(AuthGetkey *getkey, char*, ...); extern AuthInfo* auth_getinfo(AuthRpc *rpc); extern AuthRpc* auth_allocrpc(int afd); extern Attr* auth_attr(AuthRpc *rpc); extern void auth_freerpc(AuthRpc *rpc); extern uint auth_rpc(AuthRpc *rpc, char *verb, void *a, int n); extern int auth_wep(char*, char*, ...); #ifdef VARARGCK #pragma varargck argpos auth_proxy 3 #pragma varargck argpos auth_challenge 1 #pragma varargck argpos auth_respond 3 #pragma varargck argpos auth_getuserpasswd 2 #endif drawterm-20170818/include/authsrv.h000066400000000000000000000107221314554504700171150ustar00rootroot00000000000000#ifdef PLAN9 #pragma src "/sys/src/libauthsrv" #pragma lib "libauthsrv.a" #endif /* * Interface for talking to authentication server. */ typedef struct Ticket Ticket; typedef struct Ticketreq Ticketreq; typedef struct Authenticator Authenticator; typedef struct Nvrsafe Nvrsafe; typedef struct Passwordreq Passwordreq; typedef struct OChapreply OChapreply; typedef struct OMSchapreply OMSchapreply; enum { ANAMELEN= 28, /* maximum size of name in previous proto */ AERRLEN= 64, /* maximum size of errstr in previous proto */ DOMLEN= 48, /* length of an authentication domain name */ DESKEYLEN= 7, /* length of a des key for encrypt/decrypt */ CHALLEN= 8, /* length of a plan9 sk1 challenge */ NETCHLEN= 16, /* max network challenge length (used in AS protocol) */ CONFIGLEN= 14, SECRETLEN= 32, /* max length of a secret */ KEYDBOFF= 8, /* length of random data at the start of key file */ OKEYDBLEN= ANAMELEN+DESKEYLEN+4+2, /* length of an entry in old key file */ KEYDBLEN= OKEYDBLEN+SECRETLEN, /* length of an entry in key file */ OMD5LEN= 16, }; /* encryption numberings (anti-replay) */ enum { AuthTreq=1, /* ticket request */ AuthChal=2, /* challenge box request */ AuthPass=3, /* change password */ AuthOK=4, /* fixed length reply follows */ AuthErr=5, /* error follows */ AuthMod=6, /* modify user */ AuthApop=7, /* apop authentication for pop3 */ AuthOKvar=9, /* variable length reply follows */ AuthChap=10, /* chap authentication for ppp */ AuthMSchap=11, /* MS chap authentication for ppp */ AuthCram=12, /* CRAM verification for IMAP (RFC2195 & rfc2104) */ AuthHttp=13, /* http domain login */ AuthVNC=14, /* VNC server login (deprecated) */ AuthTs=64, /* ticket encrypted with server's key */ AuthTc, /* ticket encrypted with client's key */ AuthAs, /* server generated authenticator */ AuthAc, /* client generated authenticator */ AuthTp, /* ticket encrypted with client's key for password change */ AuthHr, /* http reply */ }; struct Ticketreq { char type; char authid[ANAMELEN]; /* server's encryption id */ char authdom[DOMLEN]; /* server's authentication domain */ char chal[CHALLEN]; /* challenge from server */ char hostid[ANAMELEN]; /* host's encryption id */ char uid[ANAMELEN]; /* uid of requesting user on host */ }; #define TICKREQLEN (3*ANAMELEN+CHALLEN+DOMLEN+1) struct Ticket { char num; /* replay protection */ char chal[CHALLEN]; /* server challenge */ char cuid[ANAMELEN]; /* uid on client */ char suid[ANAMELEN]; /* uid on server */ char key[DESKEYLEN]; /* nonce DES key */ }; #define TICKETLEN (CHALLEN+2*ANAMELEN+DESKEYLEN+1) struct Authenticator { char num; /* replay protection */ char chal[CHALLEN]; ulong id; /* authenticator id, ++'d with each auth */ }; #define AUTHENTLEN (CHALLEN+4+1) struct Passwordreq { char num; char old[ANAMELEN]; char new[ANAMELEN]; char changesecret; char secret[SECRETLEN]; /* new secret */ }; #define PASSREQLEN (2*ANAMELEN+1+1+SECRETLEN) struct OChapreply { uchar id; char uid[ANAMELEN]; char resp[OMD5LEN]; }; struct OMSchapreply { char uid[ANAMELEN]; char LMresp[24]; /* Lan Manager response */ char NTresp[24]; /* NT response */ }; /* * convert to/from wire format */ extern int convT2M(Ticket*, char*, char*); extern void convM2T(char*, Ticket*, char*); extern void convM2Tnoenc(char*, Ticket*); extern int convA2M(Authenticator*, char*, char*); extern void convM2A(char*, Authenticator*, char*); extern int convTR2M(Ticketreq*, char*); extern void convM2TR(char*, Ticketreq*); extern int convPR2M(Passwordreq*, char*, char*); extern void convM2PR(char*, Passwordreq*, char*); /* * convert ascii password to DES key */ extern int opasstokey(char*, char*); extern int passtokey(char*, char*); /* * Nvram interface */ enum { NVwrite = 1<<0, /* always prompt and rewrite nvram */ NVwriteonerr = 1<<1, /* prompt and rewrite nvram when corrupt */ }; struct Nvrsafe { char machkey[DESKEYLEN]; uchar machsum; char authkey[DESKEYLEN]; uchar authsum; char config[CONFIGLEN]; uchar configsum; char authid[ANAMELEN]; uchar authidsum; char authdom[DOMLEN]; uchar authdomsum; }; extern uchar nvcsum(void*, int); extern int readnvram(Nvrsafe*, int); /* * call up auth server */ extern int authdial(char *netroot, char *authdom); /* * exchange messages with auth server */ extern int _asgetticket(int, char*, char*); extern int _asrdresp(int, char*, int); extern int sslnegotiate(int, Ticket*, char**, char**); extern int srvsslnegotiate(int, Ticket*, char**, char**); drawterm-20170818/include/cursor.h000066400000000000000000000001061314554504700167310ustar00rootroot00000000000000struct Cursor { Point offset; uchar clr[2*16]; uchar set[2*16]; }; drawterm-20170818/include/draw.h000066400000000000000000000372641314554504700163700ustar00rootroot00000000000000#ifdef PLAN9 #pragma src "/sys/src/libdraw" #pragma lib "libdraw.a" #endif typedef struct Cachefont Cachefont; typedef struct Cacheinfo Cacheinfo; typedef struct Cachesubf Cachesubf; typedef struct Display Display; typedef struct Font Font; typedef struct Fontchar Fontchar; typedef struct Image Image; typedef struct Mouse Mouse; typedef struct Point Point; typedef struct Rectangle Rectangle; typedef struct RGB RGB; typedef struct Screen Screen; typedef struct Subfont Subfont; #ifdef VARARGCK #pragma varargck type "R" Rectangle #pragma varargck type "P" Point #endif extern int Rfmt(Fmt*); extern int Pfmt(Fmt*); enum { DOpaque = 0xFFFFFFFF, DTransparent = 0x00000000, /* only useful for allocimage, memfillcolor */ DBlack = 0x000000FF, DWhite = 0xFFFFFFFF, DRed = 0xFF0000FF, DGreen = 0x00FF00FF, DBlue = 0x0000FFFF, DCyan = 0x00FFFFFF, DMagenta = 0xFF00FFFF, DYellow = 0xFFFF00FF, DPaleyellow = 0xFFFFAAFF, DDarkyellow = 0xEEEE9EFF, DDarkgreen = 0x448844FF, DPalegreen = 0xAAFFAAFF, DMedgreen = 0x88CC88FF, DDarkblue = 0x000055FF, DPalebluegreen= 0xAAFFFFFF, DPaleblue = 0x0000BBFF, DBluegreen = 0x008888FF, DGreygreen = 0x55AAAAFF, DPalegreygreen = 0x9EEEEEFF, DYellowgreen = 0x99994CFF, DMedblue = 0x000099FF, DGreyblue = 0x005DBBFF, DPalegreyblue = 0x4993DDFF, DPurpleblue = 0x8888CCFF, DNotacolor = 0xFFFFFF00, DNofill = DNotacolor, }; enum { Displaybufsize = 8000, ICOSSCALE = 1024, Borderwidth = 4, }; enum { /* refresh methods */ Refbackup = 0, Refnone = 1, Refmesg = 2 }; #define NOREFRESH ((void*)-1) enum { /* line ends */ Endsquare = 0, Enddisc = 1, Endarrow = 2, Endmask = 0x1F }; #define ARROW(a, b, c) (Endarrow|((a)<<5)|((b)<<14)|((c)<<23)) typedef enum { /* Porter-Duff compositing operators */ Clear = 0, SinD = 8, DinS = 4, SoutD = 2, DoutS = 1, S = SinD|SoutD, SoverD = SinD|SoutD|DoutS, SatopD = SinD|DoutS, SxorD = SoutD|DoutS, D = DinS|DoutS, DoverS = DinS|DoutS|SoutD, DatopS = DinS|SoutD, DxorS = DoutS|SoutD, /* == SxorD */ Ncomp = 12, } Drawop; /* * image channel descriptors */ enum { CRed = 0, CGreen, CBlue, CGrey, CAlpha, CMap, CIgnore, NChan, }; #define __DC(type, nbits) ((((type)&15)<<4)|((nbits)&15)) #define CHAN1(a,b) __DC(a,b) #define CHAN2(a,b,c,d) (CHAN1((a),(b))<<8|__DC((c),(d))) #define CHAN3(a,b,c,d,e,f) (CHAN2((a),(b),(c),(d))<<8|__DC((e),(f))) #define CHAN4(a,b,c,d,e,f,g,h) (CHAN3((a),(b),(c),(d),(e),(f))<<8|__DC((g),(h))) #define NBITS(c) ((c)&15) #define TYPE(c) (((c)>>4)&15) enum { GREY1 = CHAN1(CGrey, 1), GREY2 = CHAN1(CGrey, 2), GREY4 = CHAN1(CGrey, 4), GREY8 = CHAN1(CGrey, 8), CMAP8 = CHAN1(CMap, 8), RGB15 = CHAN4(CIgnore, 1, CRed, 5, CGreen, 5, CBlue, 5), RGB16 = CHAN3(CRed, 5, CGreen, 6, CBlue, 5), RGB24 = CHAN3(CRed, 8, CGreen, 8, CBlue, 8), BGR24 = CHAN3(CBlue, 8, CGreen, 8, CRed, 8), RGBA32 = CHAN4(CRed, 8, CGreen, 8, CBlue, 8, CAlpha, 8), ARGB32 = CHAN4(CAlpha, 8, CRed, 8, CGreen, 8, CBlue, 8), /* stupid VGAs */ XRGB32 = CHAN4(CIgnore, 8, CRed, 8, CGreen, 8, CBlue, 8), XBGR32 = CHAN4(CIgnore, 8, CBlue, 8, CGreen, 8, CRed, 8), }; extern char* chantostr(char*, ulong); extern ulong strtochan(char*); extern int chantodepth(ulong); struct Point { int x; int y; }; struct Rectangle { Point min; Point max; }; typedef void (*Reffn)(Image*, Rectangle, void*); struct Screen { Display *display; /* display holding data */ int id; /* id of system-held Screen */ Image *image; /* unused; for reference only */ Image *fill; /* color to paint behind windows */ }; struct Display { QLock qlock; int locking; /*program is using lockdisplay */ int dirno; int fd; int reffd; int ctlfd; int imageid; int local; void (*error)(Display*, char*); char *devdir; char *windir; char oldlabel[64]; ulong dataqid; Image *white; Image *black; Image *opaque; Image *transparent; Image *image; uchar *buf; int bufsize; uchar *bufp; Font *defaultfont; Subfont *defaultsubfont; Image *windows; Image *screenimage; int _isnewdisplay; }; struct Image { Display *display; /* display holding data */ int id; /* id of system-held Image */ Rectangle r; /* rectangle in data area, local coords */ Rectangle clipr; /* clipping region */ int depth; /* number of bits per pixel */ ulong chan; int repl; /* flag: data replicates to tile clipr */ Screen *screen; /* 0 if not a window */ Image *next; /* next in list of windows */ }; struct RGB { ulong red; ulong green; ulong blue; }; /* * Subfonts * * given char c, Subfont *f, Fontchar *i, and Point p, one says * i = f->info+c; * draw(b, Rect(p.x+i->left, p.y+i->top, * p.x+i->left+((i+1)->x-i->x), p.y+i->bottom), * color, f->bits, Pt(i->x, i->top)); * p.x += i->width; * to draw characters in the specified color (itself an Image) in Image b. */ struct Fontchar { int x; /* left edge of bits */ uchar top; /* first non-zero scan-line */ uchar bottom; /* last non-zero scan-line + 1 */ char left; /* offset of baseline */ uchar width; /* width of baseline */ }; struct Subfont { char *name; short n; /* number of chars in font */ uchar height; /* height of image */ char ascent; /* top of image to baseline */ Fontchar *info; /* n+1 character descriptors */ Image *bits; /* of font */ int ref; }; enum { /* starting values */ LOG2NFCACHE = 6, NFCACHE = (1<>8)) #define BPLONG(p, v) (BPSHORT(p, (v)), BPSHORT(p+2, (v)>>16)) /* * Compressed image file parameters and helper routines */ #define NMATCH 3 /* shortest match possible */ #define NRUN (NMATCH+31) /* longest match possible */ #define NMEM 1024 /* window size */ #define NDUMP 128 /* maximum length of dump */ #define NCBLOCK 6000 /* size of compressed blocks */ extern void _twiddlecompressed(uchar*, int); extern int _compblocksize(Rectangle, int); /* XXX backwards helps; should go */ extern int log2[]; extern ulong drawld2chan[]; extern void drawsetdebug(int); drawterm-20170818/include/dtos.h000066400000000000000000000006401314554504700163700ustar00rootroot00000000000000#if defined(linux) || defined(IRIX) || defined(SOLARIS) || defined(OSF1) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__) || defined(__sun) || defined(sun) || defined(__OpenBSD__) # include "unix.h" # ifdef __APPLE__ # define panic dt_panic # endif #elif defined(WINDOWS) # include "9windows.h" # define main mymain #else # error "Define an OS" #endif #ifdef IRIX typedef int socklen_t; #endif drawterm-20170818/include/fcall.h000066400000000000000000000051651314554504700165070ustar00rootroot00000000000000#define VERSION9P "9P2000" #define MAXWELEM 16 typedef struct Fcall { uchar type; u32int fid; ushort tag; u32int msize; /* Tversion, Rversion */ char *version; /* Tversion, Rversion */ ushort oldtag; /* Tflush */ char *ename; /* Rerror */ Qid qid; /* Rattach, Ropen, Rcreate */ u32int iounit; /* Ropen, Rcreate */ Qid aqid; /* Rauth */ u32int afid; /* Tauth, Tattach */ char *uname; /* Tauth, Tattach */ char *aname; /* Tauth, Tattach */ u32int perm; /* Tcreate */ char *name; /* Tcreate */ uchar mode; /* Tcreate, Topen */ u32int newfid; /* Twalk */ ushort nwname; /* Twalk */ char *wname[MAXWELEM]; /* Twalk */ ushort nwqid; /* Rwalk */ Qid wqid[MAXWELEM]; /* Rwalk */ vlong offset; /* Tread, Twrite */ u32int count; /* Tread, Twrite, Rread */ char *data; /* Twrite, Rread */ ushort nstat; /* Twstat, Rstat */ uchar *stat; /* Twstat, Rstat */ } Fcall; #define GBIT8(p) ((p)[0]) #define GBIT16(p) ((p)[0]|((p)[1]<<8)) #define GBIT32(p) ((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) #define GBIT64(p) ((u32int)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\ ((vlong)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32)) #define PBIT8(p,v) (p)[0]=(v) #define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8 #define PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24 #define PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\ (p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56 #define BIT8SZ 1 #define BIT16SZ 2 #define BIT32SZ 4 #define BIT64SZ 8 #define QIDSZ (BIT8SZ+BIT32SZ+BIT64SZ) /* STATFIXLEN includes leading 16-bit count */ /* The count, however, excludes itself; total size is BIT16SZ+count */ #define STATFIXLEN (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ) /* amount of fixed length data in a stat buffer */ #define NOTAG (ushort)~0U /* Dummy tag */ #define NOFID (u32int)~0U /* Dummy fid */ #define IOHDRSZ 24 /* ample room for Twrite/Rread header (iounit) */ enum { Tversion = 100, Rversion, Tauth = 102, Rauth, Tattach = 104, Rattach, Terror = 106, /* illegal */ Rerror, Tflush = 108, Rflush, Twalk = 110, Rwalk, Topen = 112, Ropen, Tcreate = 114, Rcreate, Tread = 116, Rread, Twrite = 118, Rwrite, Tclunk = 120, Rclunk, Tremove = 122, Rremove, Tstat = 124, Rstat, Twstat = 126, Rwstat, Tmax, }; uint convM2S(uchar*, uint, Fcall*); uint convS2M(Fcall*, uchar*, uint); uint sizeS2M(Fcall*); int statcheck(uchar *abuf, uint nbuf); uint convM2D(uchar*, uint, Dir*, char*); uint convD2M(Dir*, uchar*, uint); uint sizeD2M(Dir*); int fcallfmt(Fmt*); int dirfmt(Fmt*); int dirmodefmt(Fmt*); int read9pmsg(int, void*, uint); drawterm-20170818/include/ip.h000066400000000000000000000015601314554504700160310ustar00rootroot00000000000000enum { IPaddrlen= 16, IPv4addrlen= 4, IPv4off= 12, }; uchar* defmask(uchar*); void maskip(uchar*, uchar*, uchar*); int eipfmt(Fmt*); int isv4(uchar*); vlong parseip(uchar*, char*); vlong parseipmask(uchar*, char*); char* v4parseip(uchar*, char*); char* v4parsecidr(uchar*, uchar*, char*); void hnputv(void*, uvlong); void hnputl(void*, uint); void hnputs(void*, ushort); uvlong nhgetv(void*); uint nhgetl(void*); ushort nhgets(void*); int v6tov4(uchar*, uchar*); void v4tov6(uchar*, uchar*); #define ipcmp(x, y) memcmp(x, y, IPaddrlen) #define ipmove(x, y) memmove(x, y, IPaddrlen) extern uchar IPv4bcast[IPaddrlen]; extern uchar IPv4bcastobs[IPaddrlen]; extern uchar IPv4allsys[IPaddrlen]; extern uchar IPv4allrouter[IPaddrlen]; extern uchar IPnoaddr[IPaddrlen]; extern uchar v4prefix[IPaddrlen]; extern uchar IPallbits[IPaddrlen]; #define CLASS(p) ((*(uchar*)(p))>>6) drawterm-20170818/include/keyboard.h000066400000000000000000000016521314554504700172230ustar00rootroot00000000000000#ifdef PLAN9 #pragma src "/sys/src/libdraw" #pragma lib "libdraw.a" #endif typedef struct Keyboardctl Keyboardctl; typedef struct Channel Channel; struct Keyboardctl { Channel *c; /* chan(Rune)[20] */ char *file; int consfd; /* to cons file */ int ctlfd; /* to ctl file */ int pid; /* of slave proc */ }; extern Keyboardctl* initkeyboard(char*); extern int ctlkeyboard(Keyboardctl*, char*); extern void closekeyboard(Keyboardctl*); enum { KF= 0xF000, /* Rune: beginning of private Unicode space */ Kdel= 0x7F, Spec= 0xF800, /* KF|1, KF|2, ..., KF|0xC is F1, F2, ..., F12 */ Khome= KF|0x0D, Kup= KF|0x0E, Kpgup= KF|0x0F, Kprint= KF|0x10, Kleft= KF|0x11, Kright= KF|0x12, Kdown= Spec|0x00, Kview= Spec|0x00, Kpgdown= KF|0x13, Kins= KF|0x14, Kend= KF|0x18, Kalt= KF|0x15, Kshift= KF|0x16, Kctl= KF|0x17, }; drawterm-20170818/include/lib.h000066400000000000000000000173671314554504700162030ustar00rootroot00000000000000/* avoid name conflicts */ #define accept pm_accept #define listen pm_listen #define sleep ksleep #define wakeup kwakeup #ifdef strtod #undef strtod #endif #define strtod fmtstrtod /* conflicts on some os's */ #define encrypt libencrypt #define decrypt libdecrypt #define oserror liboserror #define clone libclone #define atexit libatexit #define log2 liblog2 #define log liblog #define reboot libreboot #ifdef strtoll #undef strtoll #define strtoll libstrtoll #endif #undef timeradd #define timeradd xtimeradd #define nil ((void*)0) typedef unsigned char p9_uchar; typedef unsigned int p9_uint; typedef unsigned int p9_ulong; typedef int p9_long; typedef signed char p9_schar; typedef unsigned short p9_ushort; typedef unsigned int Rune; typedef unsigned int p9_u32int; typedef p9_u32int mpdigit; /* make sure we don't conflict with predefined types */ #define schar p9_schar #define uchar p9_uchar #define ushort p9_ushort #define uint p9_uint #define u32int p9_u32int /* #define long int rather than p9_long so that "unsigned long" is valid */ #define long int #define ulong p9_ulong #define vlong p9_vlong #define uvlong p9_uvlong #define nelem(x) (sizeof(x)/sizeof((x)[0])) #define SET(x) ((x)=0) #define USED(x) if(x);else enum { UTFmax = 4, /* maximum bytes per rune */ Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ Runeself = 0x80, /* rune and UTF sequences are the same (<) */ Runeerror = 0xFFFD, /* decoding error in UTF */ Runemax = 0x10FFFF, /* 21-bit rune */ Runemask = 0x1FFFFF, /* bits used by runes (see grep) */ }; /* * new rune routines */ extern int runetochar(char*, Rune*); extern int chartorune(Rune*, char*); extern int runelen(long); extern int fullrune(char*, int); extern int wstrtoutf(char*, Rune*, int); extern int wstrutflen(Rune*); /* * rune routines from converted str routines */ extern long utflen(char*); extern char* utfrune(char*, long); extern char* utfrrune(char*, long); /* * Syscall data structures */ #define MORDER 0x0003 /* mask for bits defining order of mounting */ #define MREPL 0x0000 /* mount replaces object */ #define MBEFORE 0x0001 /* mount goes before others in union directory */ #define MAFTER 0x0002 /* mount goes after others in union directory */ #define MCREATE 0x0004 /* permit creation in mounted directory */ #define MCACHE 0x0010 /* cache some data */ #define MMASK 0x0017 /* all bits on */ #define OREAD 0 /* open for read */ #define OWRITE 1 /* write */ #define ORDWR 2 /* read and write */ #define OEXEC 3 /* execute, == read but check execute permission */ #define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ #define OCEXEC 32 /* or'ed in, close on exec */ #define ORCLOSE 64 /* or'ed in, remove on close */ #define OEXCL 0x1000 /* or'ed in, exclusive create */ #define NCONT 0 /* continue after note */ #define NDFLT 1 /* terminate after note */ #define NSAVE 2 /* clear note but hold state */ #define NRSTR 3 /* restore saved state */ #define ERRMAX 128 /* max length of error string */ #define KNAMELEN 28 /* max length of name held in kernel */ /* bits in Qid.type */ #define QTDIR 0x80 /* type bit for directories */ #define QTAPPEND 0x40 /* type bit for append only files */ #define QTEXCL 0x20 /* type bit for exclusive use files */ #define QTMOUNT 0x10 /* type bit for mounted channel */ #define QTAUTH 0x08 /* type bit for authentication file */ #define QTFILE 0x00 /* plain file */ /* bits in Dir.mode */ #define DMDIR 0x80000000 /* mode bit for directories */ #define DMAPPEND 0x40000000 /* mode bit for append only files */ #define DMEXCL 0x20000000 /* mode bit for exclusive use files */ #define DMMOUNT 0x10000000 /* mode bit for mounted channel */ #define DMAUTH 0x08000000 /* mode bit for authentication files */ #define DMREAD 0x4 /* mode bit for read permission */ #define DMWRITE 0x2 /* mode bit for write permission */ #define DMEXEC 0x1 /* mode bit for execute permission */ typedef struct Lock { #ifdef PTHREAD int init; pthread_mutex_t mutex; #else long key; #endif } Lock; typedef struct QLock { Lock lk; struct Proc *hold; struct Proc *first; struct Proc *last; } QLock; typedef struct Qid { uvlong path; ulong vers; uchar type; } Qid; typedef struct Dir { /* system-modified data */ ushort type; /* server type */ uint dev; /* server subtype */ /* file data */ Qid qid; /* unique id from server */ ulong mode; /* permissions */ ulong atime; /* last read time */ ulong mtime; /* last write time */ vlong length; /* file length */ char *name; /* last element of path */ char *uid; /* owner name */ char *gid; /* group name */ char *muid; /* last modifier name */ } Dir; typedef struct Waitmsg { int pid; /* of loved one */ ulong time[3]; /* of loved one & descendants */ char *msg; } Waitmsg; /* * print routines */ typedef struct Fmt Fmt; struct Fmt{ uchar runes; /* output buffer is runes or chars? */ void *start; /* of buffer */ void *to; /* current place in the buffer */ void *stop; /* end of the buffer; overwritten if flush fails */ int (*flush)(Fmt *); /* called when to == stop */ void *farg; /* to make flush a closure */ int nfmt; /* num chars formatted so far */ va_list args; /* args passed to dofmt */ int r; /* % format Rune */ int width; int prec; ulong flags; }; enum{ FmtWidth = 1, FmtLeft = FmtWidth << 1, FmtPrec = FmtLeft << 1, FmtSharp = FmtPrec << 1, FmtSpace = FmtSharp << 1, FmtSign = FmtSpace << 1, FmtZero = FmtSign << 1, FmtUnsigned = FmtZero << 1, FmtShort = FmtUnsigned << 1, FmtLong = FmtShort << 1, FmtVLong = FmtLong << 1, FmtComma = FmtVLong << 1, FmtByte = FmtComma << 1, FmtFlag = FmtByte << 1, FmtLDouble = FmtFlag << 1 }; extern int print(char*, ...); extern char* seprint(char*, char*, char*, ...); extern char* vseprint(char*, char*, char*, va_list); extern int snprint(char*, int, char*, ...); extern int vsnprint(char*, int, char*, va_list); extern char* smprint(char*, ...); extern char* vsmprint(char*, va_list); extern int sprint(char*, char*, ...); extern int fprint(int, char*, ...); extern int vfprint(int, char*, va_list); extern int (*doquote)(int); extern int runesprint(Rune*, char*, ...); extern int runesnprint(Rune*, int, char*, ...); extern int runevsnprint(Rune*, int, char*, va_list); extern Rune* runeseprint(Rune*, Rune*, char*, ...); extern Rune* runevseprint(Rune*, Rune*, char*, va_list); extern Rune* runesmprint(char*, ...); extern Rune* runevsmprint(char*, va_list); extern Rune* runestrchr(Rune*, Rune); extern long runestrlen(Rune*); extern Rune* runestrstr(Rune*, Rune*); extern int fmtfdinit(Fmt*, int, char*, int); extern int fmtfdflush(Fmt*); extern int fmtstrinit(Fmt*); extern int fmtinstall(int, int (*)(Fmt*)); extern char* fmtstrflush(Fmt*); extern int runefmtstrinit(Fmt*); extern Rune* runefmtstrflush(Fmt*); extern int encodefmt(Fmt*); extern int fmtstrcpy(Fmt*, char*); extern int fmtprint(Fmt*, char*, ...); extern int fmtvprint(Fmt*, char*, va_list); extern void* mallocz(ulong, int); extern uintptr getcallerpc(void*); extern char* cleanname(char*); extern void sysfatal(char*, ...); extern char* strecpy(char*, char*, char*); extern int tokenize(char*, char**, int); extern int getfields(char*, char**, int, int, char*); extern char* utfecpy(char*, char*, char*); extern long tas(long*); extern void quotefmtinstall(void); extern int dec64(uchar*, int, char*, int); extern int enc64(char*, int, uchar*, int); extern int dec32(uchar*, int, char*, int); extern int enc32(char*, int, uchar*, int); extern int enc16(char*, int, uchar*, int); void hnputs(void *p, unsigned short v); extern int dofmt(Fmt*, char*); extern double __NaN(void); extern int __isNaN(double); extern double strtod(const char*, char**); extern int utfnlen(char*, long); extern double __Inf(int); extern int __isInf(double, int); extern int (*fmtdoquote)(int); drawterm-20170818/include/libc.h000066400000000000000000000000441314554504700163260ustar00rootroot00000000000000#include "lib.h" #include "user.h" drawterm-20170818/include/libsec.h000066400000000000000000000212351314554504700166630ustar00rootroot00000000000000 #ifndef _MPINT typedef struct mpint mpint; #endif ///////////////////////////////////////////////////////// // AES definitions ///////////////////////////////////////////////////////// enum { AESbsize= 16, AESmaxkey= 32, AESmaxrounds= 14 }; typedef struct AESstate AESstate; struct AESstate { ulong setup; int rounds; int keybytes; uchar key[AESmaxkey]; /* unexpanded key */ u32int ekey[4*(AESmaxrounds + 1)]; /* encryption key */ u32int dkey[4*(AESmaxrounds + 1)]; /* decryption key */ uchar ivec[AESbsize]; /* initialization vector */ }; void setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec); void aesCBCencrypt(uchar *p, int len, AESstate *s); void aesCBCdecrypt(uchar *p, int len, AESstate *s); ///////////////////////////////////////////////////////// // Blowfish Definitions ///////////////////////////////////////////////////////// enum { BFbsize = 8, BFrounds = 16 }; // 16-round Blowfish typedef struct BFstate BFstate; struct BFstate { ulong setup; uchar key[56]; uchar ivec[8]; u32int pbox[BFrounds+2]; u32int sbox[1024]; }; void setupBFstate(BFstate *s, uchar key[], int keybytes, uchar *ivec); void bfCBCencrypt(uchar*, int, BFstate*); void bfCBCdecrypt(uchar*, int, BFstate*); void bfECBencrypt(uchar*, int, BFstate*); void bfECBdecrypt(uchar*, int, BFstate*); ///////////////////////////////////////////////////////// // DES definitions ///////////////////////////////////////////////////////// enum { DESbsize= 8 }; // single des typedef struct DESstate DESstate; struct DESstate { ulong setup; uchar key[8]; /* unexpanded key */ ulong expanded[32]; /* expanded key */ uchar ivec[8]; /* initialization vector */ }; void setupDESstate(DESstate *s, uchar key[8], uchar *ivec); void des_key_setup(uchar[8], ulong[32]); void block_cipher(ulong*, uchar*, int); void desCBCencrypt(uchar*, int, DESstate*); void desCBCdecrypt(uchar*, int, DESstate*); void desECBencrypt(uchar*, int, DESstate*); void desECBdecrypt(uchar*, int, DESstate*); // for backward compatibility with 7 byte DES key format void des56to64(uchar *k56, uchar *k64); void des64to56(uchar *k64, uchar *k56); void key_setup(uchar[7], ulong[32]); // triple des encrypt/decrypt orderings enum { DES3E= 0, DES3D= 1, DES3EEE= 0, DES3EDE= 2, DES3DED= 5, DES3DDD= 7 }; typedef struct DES3state DES3state; struct DES3state { ulong setup; uchar key[3][8]; /* unexpanded key */ ulong expanded[3][32]; /* expanded key */ uchar ivec[8]; /* initialization vector */ }; void setupDES3state(DES3state *s, uchar key[3][8], uchar *ivec); void triple_block_cipher(ulong keys[3][32], uchar*, int); void des3CBCencrypt(uchar*, int, DES3state*); void des3CBCdecrypt(uchar*, int, DES3state*); void des3ECBencrypt(uchar*, int, DES3state*); void des3ECBdecrypt(uchar*, int, DES3state*); ///////////////////////////////////////////////////////// // digests ///////////////////////////////////////////////////////// enum { SHA1dlen= 20, /* SHA digest length */ MD4dlen= 16, /* MD4 digest length */ MD5dlen= 16 /* MD5 digest length */ }; typedef struct DigestState DigestState; struct DigestState { ulong len; u32int state[5]; uchar buf[128]; int blen; char malloced; char seeded; }; typedef struct DigestState SHAstate; /* obsolete name */ typedef struct DigestState SHA1state; typedef struct DigestState MD5state; typedef struct DigestState MD4state; DigestState* md4(uchar*, ulong, uchar*, DigestState*); DigestState* md5(uchar*, ulong, uchar*, DigestState*); DigestState* sha1(uchar*, ulong, uchar*, DigestState*); DigestState* hmac_md5(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); DigestState* hmac_sha1(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); char* sha1pickle(SHA1state*); SHA1state* sha1unpickle(char*); ///////////////////////////////////////////////////////// // random number generation ///////////////////////////////////////////////////////// void genrandom(uchar *buf, int nbytes); void prng(uchar *buf, int nbytes); ulong fastrand(void); ulong nfastrand(ulong); ///////////////////////////////////////////////////////// // primes ///////////////////////////////////////////////////////// void genprime(mpint *p, int n, int accuracy); // generate an n bit probable prime void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy); // prime and generator void genstrongprime(mpint *p, int n, int accuracy); // generate an n bit strong prime void DSAprimes(mpint *q, mpint *p, uchar seed[SHA1dlen]); int probably_prime(mpint *n, int nrep); // miller-rabin test int smallprimetest(mpint *p); // returns -1 if not prime, 0 otherwise ///////////////////////////////////////////////////////// // rc4 ///////////////////////////////////////////////////////// typedef struct RC4state RC4state; struct RC4state { uchar state[256]; uchar x; uchar y; }; void setupRC4state(RC4state*, uchar*, int); void rc4(RC4state*, uchar*, int); void rc4skip(RC4state*, int); void rc4back(RC4state*, int); ///////////////////////////////////////////////////////// // rsa ///////////////////////////////////////////////////////// typedef struct RSApub RSApub; typedef struct RSApriv RSApriv; // public/encryption key struct RSApub { mpint *n; // modulus mpint *ek; // exp (encryption key) }; // private/decryption key struct RSApriv { RSApub pub; mpint *dk; // exp (decryption key) // precomputed values to help with chinese remainder theorem calc mpint *p; mpint *q; mpint *kp; // dk mod p-1 mpint *kq; // dk mod q-1 mpint *c2; // (inv p) mod q }; RSApriv* rsagen(int nlen, int elen, int rounds); RSApriv* rsafill(mpint *n, mpint *e, mpint *d, mpint *p, mpint *q); mpint* rsaencrypt(RSApub *k, mpint *in, mpint *out); mpint* rsadecrypt(RSApriv *k, mpint *in, mpint *out); RSApub* rsapuballoc(void); void rsapubfree(RSApub*); RSApriv* rsaprivalloc(void); void rsaprivfree(RSApriv*); RSApub* rsaprivtopub(RSApriv*); RSApub* X509toRSApub(uchar*, int, char*, int); RSApriv* asn1toRSApriv(uchar*, int); void asn1dump(uchar *der, int len); uchar* decodepem(char *s, char *type, int *len); uchar* X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen); uchar* X509req(RSApriv *priv, char *subj, int *certlen); char* X509verify(uchar *cert, int ncert, RSApub *pk); void X509dump(uchar *cert, int ncert); ///////////////////////////////////////////////////////// // elgamal ///////////////////////////////////////////////////////// typedef struct EGpub EGpub; typedef struct EGpriv EGpriv; typedef struct EGsig EGsig; // public/encryption key struct EGpub { mpint *p; // modulus mpint *alpha; // generator mpint *key; // (encryption key) alpha**secret mod p }; // private/decryption key struct EGpriv { EGpub pub; mpint *secret; // (decryption key) }; // signature struct EGsig { mpint *r, *s; }; EGpriv* eggen(int nlen, int rounds); mpint* egencrypt(EGpub *k, mpint *in, mpint *out); mpint* egdecrypt(EGpriv *k, mpint *in, mpint *out); EGsig* egsign(EGpriv *k, mpint *m); int egverify(EGpub *k, EGsig *sig, mpint *m); EGpub* egpuballoc(void); void egpubfree(EGpub*); EGpriv* egprivalloc(void); void egprivfree(EGpriv*); EGsig* egsigalloc(void); void egsigfree(EGsig*); EGpub* egprivtopub(EGpriv*); ///////////////////////////////////////////////////////// // dsa ///////////////////////////////////////////////////////// typedef struct DSApub DSApub; typedef struct DSApriv DSApriv; typedef struct DSAsig DSAsig; // public/encryption key struct DSApub { mpint *p; // modulus mpint *q; // group order, q divides p-1 mpint *alpha; // group generator mpint *key; // (encryption key) alpha**secret mod p }; // private/decryption key struct DSApriv { DSApub pub; mpint *secret; // (decryption key) }; // signature struct DSAsig { mpint *r, *s; }; DSApriv* dsagen(DSApub *opub); DSAsig* dsasign(DSApriv *k, mpint *m); int dsaverify(DSApub *k, DSAsig *sig, mpint *m); DSApub* dsapuballoc(void); void dsapubfree(DSApub*); DSApriv* dsaprivalloc(void); void dsaprivfree(DSApriv*); DSAsig* dsasigalloc(void); void dsasigfree(DSAsig*); DSApub* dsaprivtopub(DSApriv*); ///////////////////////////////////////////////////////// // TLS ///////////////////////////////////////////////////////// typedef struct Thumbprint{ struct Thumbprint *next; uchar sha1[SHA1dlen]; } Thumbprint; typedef struct TLSconn{ char dir[40]; // connection directory uchar *cert; // certificate (local on input, remote on output) uchar *sessionID; int certlen, sessionIDlen; int (*trace)(char*fmt, ...); } TLSconn; // tlshand.c extern int tlsClient(int fd, TLSconn *c); extern int tlsServer(int fd, TLSconn *c); // thumb.c extern Thumbprint* initThumbprints(char *ok, char *crl); extern void freeThumbprints(Thumbprint *ok); extern int okThumbprint(uchar *sha1, Thumbprint *ok); // readcert.c extern uchar *readcert(char *filename, int *pcertlen); drawterm-20170818/include/memdraw.h000066400000000000000000000142421314554504700170560ustar00rootroot00000000000000#ifdef PLAN9 #pragma src "/sys/src/libmemdraw" #pragma lib "libmemdraw.a" #endif typedef struct Memimage Memimage; typedef struct Memdata Memdata; typedef struct Memsubfont Memsubfont; typedef struct Memlayer Memlayer; typedef struct Memcmap Memcmap; typedef struct Memdrawparam Memdrawparam; /* * Memdata is allocated from main pool, but .data from the image pool. * Memdata is allocated separately to permit patching its pointer after * compaction when windows share the image data. * The first word of data is a back pointer to the Memdata, to find * The word to patch. */ struct Memdata { ulong *base; /* allocated data pointer */ uchar *bdata; /* pointer to first byte of actual data; word-aligned */ int ref; /* number of Memimages using this data */ void* imref; int allocd; /* is this malloc'd? */ }; enum { Frepl = 1<<0, /* is replicated */ Fsimple = 1<<1, /* is 1x1 */ Fgrey = 1<<2, /* is grey */ Falpha = 1<<3, /* has explicit alpha */ Fcmap = 1<<4, /* has cmap channel */ Fbytes = 1<<5, /* has only 8-bit channels */ }; struct Memimage { Rectangle r; /* rectangle in data area, local coords */ Rectangle clipr; /* clipping region */ int depth; /* number of bits of storage per pixel */ int nchan; /* number of channels */ ulong chan; /* channel descriptions */ Memcmap *cmap; Memdata *data; /* pointer to data; shared by windows in this image */ int zero; /* data->bdata+zero==&byte containing (0,0) */ ulong width; /* width in words of a single scan line */ Memlayer *layer; /* nil if not a layer*/ ulong flags; int shift[NChan]; int mask[NChan]; int nbits[NChan]; void *X; }; struct Memcmap { uchar cmap2rgb[3*256]; uchar rgb2cmap[16*16*16]; }; /* * Subfonts * * given char c, Subfont *f, Fontchar *i, and Point p, one says * i = f->info+c; * draw(b, Rect(p.x+i->left, p.y+i->top, * p.x+i->left+((i+1)->x-i->x), p.y+i->bottom), * color, f->bits, Pt(i->x, i->top)); * p.x += i->width; * to draw characters in the specified color (itself a Memimage) in Memimage b. */ struct Memsubfont { char *name; short n; /* number of chars in font */ uchar height; /* height of bitmap */ char ascent; /* top of bitmap to baseline */ Fontchar *info; /* n+1 character descriptors */ Memimage *bits; /* of font */ }; /* * Encapsulated parameters and information for sub-draw routines. */ enum { Simplesrc=1<<0, Simplemask=1<<1, Replsrc=1<<2, Replmask=1<<3, Fullmask=1<<4, }; struct Memdrawparam { Memimage *dst; Rectangle r; Memimage *src; Rectangle sr; Memimage *mask; Rectangle mr; int op; ulong state; ulong mval; /* if Simplemask, the mask pixel in mask format */ ulong mrgba; /* mval in rgba */ ulong sval; /* if Simplesrc, the source pixel in src format */ ulong srgba; /* sval in rgba */ ulong sdval; /* sval in dst format */ }; /* * Memimage management */ extern Memimage* allocmemimage(Rectangle, ulong); extern Memimage* _allocmemimage(Rectangle, ulong); extern Memimage* allocmemimaged(Rectangle, ulong, Memdata*, void*); extern Memimage* readmemimage(int); extern Memimage* creadmemimage(int); extern int writememimage(int, Memimage*); extern void freememimage(Memimage*); extern void _freememimage(Memimage*); extern int _loadmemimage(Memimage*, Rectangle, uchar*, int); extern int _cloadmemimage(Memimage*, Rectangle, uchar*, int); extern int _unloadmemimage(Memimage*, Rectangle, uchar*, int); extern int loadmemimage(Memimage*, Rectangle, uchar*, int); extern int cloadmemimage(Memimage*, Rectangle, uchar*, int); extern int unloadmemimage(Memimage*, Rectangle, uchar*, int); extern ulong* wordaddr(Memimage*, Point); extern uchar* byteaddr(Memimage*, Point); extern int drawclip(Memimage*, Rectangle*, Memimage*, Point*, Memimage*, Point*, Rectangle*, Rectangle*); extern void memfillcolor(Memimage*, ulong); extern void _memfillcolor(Memimage*, ulong); extern int memsetchan(Memimage*, ulong); extern ulong _rgbatoimg(Memimage*, ulong); /* * Graphics */ extern void memdraw(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int); extern void memline(Memimage*, Point, Point, int, int, int, Memimage*, Point, int); extern void mempoly(Memimage*, Point*, int, int, int, int, Memimage*, Point, int); extern void memfillpoly(Memimage*, Point*, int, int, Memimage*, Point, int); extern void _memfillpolysc(Memimage*, Point*, int, int, Memimage*, Point, int, int, int, int); extern Memdrawparam* _memimagedrawsetup(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int); extern void _memimagedraw(Memdrawparam*); extern void memimagedraw(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int); extern int hwdraw(Memdrawparam*); extern void memimageline(Memimage*, Point, Point, int, int, int, Memimage*, Point, int); extern void _memimageline(Memimage*, Point, Point, int, int, int, Memimage*, Point, Rectangle, int); extern Point memimagestring(Memimage*, Point, Memimage*, Point, Memsubfont*, char*); extern void memellipse(Memimage*, Point, int, int, int, Memimage*, Point, int); extern void memarc(Memimage*, Point, int, int, int, Memimage*, Point, int, int, int); extern Rectangle memlinebbox(Point, Point, int, int, int); extern int memlineendsize(int); extern void _memmkcmap(void); extern void _memimageinit(void); extern void memimageinit(void); /* * Subfont management */ extern Memsubfont* allocmemsubfont(char*, int, int, int, Fontchar*, Memimage*); extern Memsubfont* openmemsubfont(char*); extern void freememsubfont(Memsubfont*); extern Point memsubfontwidth(Memsubfont*, char*); extern Memsubfont* getmemdefont(void); /* * Predefined */ extern Memimage* memwhite; extern Memimage* memblack; extern Memimage* memopaque; extern Memimage* memtransparent; extern Memcmap *memdefcmap; /* * Kernel interface */ void memimagemove(void*, void*); /* * Kernel cruft */ extern void rdb(void); extern int iprint(char*, ...); extern int drawdebug; /* * doprint interface: numbconv bit strings */ #ifdef VARARGCK #pragma varargck argpos iprint 1 #pragma varargck type "llb" vlong #pragma varargck type "llb" uvlong #pragma varargck type "lb" long #pragma varargck type "lb" ulong #pragma varargck type "b" int #pragma varargck type "b" uint #endif extern ulong _pixelbits(Memimage*,Point); extern ulong pixelbits(Memimage*, Point); drawterm-20170818/include/memlayer.h000066400000000000000000000035171314554504700172400ustar00rootroot00000000000000#ifdef PLAN9 #pragma src "/sys/src/libmemlayer" #pragma lib "libmemlayer.a" #endif typedef struct Memscreen Memscreen; typedef void (*Refreshfn)(Memimage*, Rectangle, void*); struct Memscreen { Memimage *frontmost; /* frontmost layer on screen */ Memimage *rearmost; /* rearmost layer on screen */ Memimage *image; /* upon which all layers are drawn */ Memimage *fill; /* if non-zero, picture to use when repainting */ }; struct Memlayer { Rectangle screenr; /* true position of layer on screen */ Point delta; /* add delta to go from image coords to screen */ Memscreen *screen; /* screen this layer belongs to */ Memimage *front; /* window in front of this one */ Memimage *rear; /* window behind this one*/ int clear; /* layer is fully visible */ Memimage *save; /* save area for obscured parts */ Refreshfn refreshfn; /* function to call to refresh obscured parts if save==nil */ void *refreshptr; /* argument to refreshfn */ }; /* * These functions accept local coordinates */ int memload(Memimage*, Rectangle, uchar*, int, int); int memunload(Memimage*, Rectangle, uchar*, int); /* * All these functions accept screen coordinates, not local ones. */ void _memlayerop(void (*fn)(Memimage*, Rectangle, Rectangle, void*, int), Memimage*, Rectangle, Rectangle, void*); Memimage* memlalloc(Memscreen*, Rectangle, Refreshfn, void*, ulong); void memldelete(Memimage*); void memlfree(Memimage*); void memltofront(Memimage*); void memltofrontn(Memimage**, int); void _memltofrontfill(Memimage*, int); void memltorear(Memimage*); void memltorearn(Memimage**, int); int memlsetrefresh(Memimage*, Refreshfn, void*); void memlhide(Memimage*, Rectangle); void memlexpose(Memimage*, Rectangle); void _memlsetclear(Memscreen*); int memlorigin(Memimage*, Point, Point); void memlnorefresh(Memimage*, Rectangle, void*); drawterm-20170818/include/mp.h000066400000000000000000000106541314554504700160410ustar00rootroot00000000000000#define _MPINT 1 // the code assumes mpdigit to be at least an int // mpdigit must be an atomic type. mpdigit is defined // in the architecture specific u.h typedef struct mpint mpint; struct mpint { int sign; // +1 or -1 int size; // allocated digits int top; // significant digits mpdigit *p; char flags; }; enum { MPstatic= 0x01, Dbytes= sizeof(mpdigit), // bytes per digit Dbits= Dbytes*8 // bits per digit }; // allocation void mpsetminbits(int n); // newly created mpint's get at least n bits mpint* mpnew(int n); // create a new mpint with at least n bits void mpfree(mpint *b); void mpbits(mpint *b, int n); // ensure that b has at least n bits void mpnorm(mpint *b); // dump leading zeros mpint* mpcopy(mpint *b); void mpassign(mpint *old, mpint *new); // random bits mpint* mprand(int bits, void (*gen)(uchar*, int), mpint *b); // conversion mpint* strtomp(char*, char**, int, mpint*); // ascii int mpfmt(Fmt*); char* mptoa(mpint*, int, char*, int); mpint* letomp(uchar*, uint, mpint*); // byte array, little-endian int mptole(mpint*, uchar*, uint, uchar**); mpint* betomp(uchar*, uint, mpint*); // byte array, little-endian int mptobe(mpint*, uchar*, uint, uchar**); uint mptoui(mpint*); // unsigned int mpint* uitomp(uint, mpint*); int mptoi(mpint*); // int mpint* itomp(int, mpint*); uvlong mptouv(mpint*); // unsigned vlong mpint* uvtomp(uvlong, mpint*); vlong mptov(mpint*); // vlong mpint* vtomp(vlong, mpint*); // divide 2 digits by one void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient); // in the following, the result mpint may be // the same as one of the inputs. void mpadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2 void mpsub(mpint *b1, mpint *b2, mpint *diff); // diff = b1-b2 void mpleft(mpint *b, int shift, mpint *res); // res = b<>shift void mpmul(mpint *b1, mpint *b2, mpint *prod); // prod = b1*b2 void mpexp(mpint *b, mpint *e, mpint *m, mpint *res); // res = b**e mod m void mpmod(mpint *b, mpint *m, mpint *remainder); // remainder = b mod m // quotient = dividend/divisor, remainder = dividend % divisor void mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder); // return neg, 0, pos as b1-b2 is neg, 0, pos int mpcmp(mpint *b1, mpint *b2); // extended gcd return d, x, and y, s.t. d = gcd(a,b) and ax+by = d void mpextendedgcd(mpint *a, mpint *b, mpint *d, mpint *x, mpint *y); // res = b**-1 mod m void mpinvert(mpint *b, mpint *m, mpint *res); // bit counting int mpsignif(mpint*); // number of sigificant bits in mantissa int mplowbits0(mpint*); // k, where n = 2**k * q for odd q // well known constants extern mpint *mpzero, *mpone, *mptwo; // sum[0:alen] = a[0:alen-1] + b[0:blen-1] // prereq: alen >= blen, sum has room for alen+1 digits void mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum); // diff[0:alen-1] = a[0:alen-1] - b[0:blen-1] // prereq: alen >= blen, diff has room for alen digits void mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff); // p[0:n] += m * b[0:n-1] // prereq: p has room for n+1 digits void mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p); // p[0:n] -= m * b[0:n-1] // prereq: p has room for n+1 digits int mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p); // p[0:alen*blen-1] = a[0:alen-1] * b[0:blen-1] // prereq: alen >= blen, p has room for m*n digits void mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p); // sign of a - b or zero if the same int mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen); // divide the 2 digit dividend by the one digit divisor and stick in quotient // we assume that the result is one digit - overflow is all 1's void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient); // playing with magnitudes int mpmagcmp(mpint *b1, mpint *b2); void mpmagadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2 void mpmagsub(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2 // chinese remainder theorem typedef struct CRTpre CRTpre; // precomputed values for converting // twixt residues and mpint typedef struct CRTres CRTres; // residue form of an mpint struct CRTres { int n; // number of residues mpint *r[1]; // residues }; CRTpre* crtpre(int, mpint**); // precompute conversion values CRTres* crtin(CRTpre*, mpint*); // convert mpint to residues void crtout(CRTpre*, CRTres*, mpint*); // convert residues to mpint void crtprefree(CRTpre*); void crtresfree(CRTres*); drawterm-20170818/include/u.h000066400000000000000000000005201314554504700156600ustar00rootroot00000000000000#include "dtos.h" /* avoid name conflicts */ #undef accept #undef listen /* sys calls */ #undef bind #undef chdir #undef close #undef create #undef dup #undef export #undef fstat #undef fwstat #undef mount #undef open #undef start #undef read #undef remove #undef seek #undef stat #undef write #undef wstat #undef unmount #undef pipe drawterm-20170818/include/unix.h000066400000000000000000000014321314554504700164020ustar00rootroot00000000000000#undef _FORTIFY_SOURCE /* stupid ubuntu warnings */ #define __BSD_VISIBLE 1 /* FreeBSD 5.x */ #define _BSD_SOURCE 1 #define _NETBSD_SOURCE 1 /* NetBSD */ #define _SVID_SOURCE 1 #define _DEFAULT_SOURCE 1 #if !defined(__APPLE__) && !defined(__OpenBSD__) # define _XOPEN_SOURCE 1000 # define _XOPEN_SOURCE_EXTENDED 1 #endif #define _LARGEFILE64_SOURCE 1 #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef PTHREAD #include #endif typedef long long p9_vlong; typedef unsigned long long p9_uvlong; typedef uintptr_t uintptr; drawterm-20170818/include/user.h000066400000000000000000000047461314554504700164100ustar00rootroot00000000000000/* sys calls */ #define bind sysbind #define chdir syschdir #define close sysclose #define create syscreate #define dup sysdup #define export sysexport #define fstat sysfstat #define fwstat sysfwstat #define mount sysmount #define open sysopen #define read sysread #define remove sysremove #define seek sysseek #define stat sysstat #define write syswrite #define wstat syswstat #define unmount sysunmount #define pipe syspipe #define rendezvous sysrendezvous #define getpid sysgetpid #define time systime #define nsec sysnsec #define pread syspread #define pwrite syspwrite #undef sleep #define sleep osmsleep extern int bind(char*, char*, int); extern int chdir(char*); extern int close(int); extern int create(char*, int, ulong); extern int dup(int, int); extern int export(int); extern int fstat(int, uchar*, int); extern int fwstat(int, uchar*, int); extern int mount(int, int, char*, int, char*); extern int unmount(char*, char*); extern int open(char*, int); extern int pipe(int*); extern long read(int, void*, long); extern long readn(int, void*, long); extern int remove(char*); extern vlong seek(int, vlong, int); extern int stat(char*, uchar*, int); extern long write(int, void*, long); extern int wstat(char*, uchar*, int); extern void werrstr(char* ,...); extern Dir *dirstat(char*); extern Dir *dirfstat(int); extern int dirwstat(char*, Dir*); extern int dirfwstat(int, Dir*); extern long dirread(int, Dir*, long); extern int lfdfd(int); /* * network dialing and authentication */ #define NETPATHLEN 40 extern int accept(int, char*); extern int announce(char*, char*); extern int dial(char*, char*, char*, int*); extern int hangup(int); extern int listen(char*, char*); extern char *netmkaddr(char*, char*, char*); extern int reject(int, char*, char*); extern char* argv0; extern ulong truerand(void); extern int pushssl(int, char*, char*, char*, int*); extern int iounit(int); extern long pread(int, void*, long, vlong); extern long pwrite(int, void*, long, vlong); extern void* rendezvous(void*, void*); extern int kproc(char*, void(*)(void*), void*); extern int getpid(void); extern void panic(char*, ...); extern void sleep(int); extern void osyield(void); extern void setmalloctag(void*, uintptr); extern int errstr(char*, uint); extern int rerrstr(char*, uint); extern int encrypt(void*, void*, int); extern int decrypt(void*, void*, int); extern void qlock(QLock*); extern void qunlock(QLock*); extern vlong nsec(void); extern void lock(Lock*); extern void unlock(Lock*); extern int iprint(char*, ...); drawterm-20170818/include/x000066400000000000000000000000001314554504700154260ustar00rootroot00000000000000drawterm-20170818/include/x.c000066400000000000000000000000501314554504700156540ustar00rootroot00000000000000#include void main(void) { } drawterm-20170818/kern/000077500000000000000000000000001314554504700145625ustar00rootroot00000000000000drawterm-20170818/kern/Makefile000066400000000000000000000011421314554504700162200ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libkern.a OFILES=\ allocb.$O\ cache.$O\ chan.$O\ data.$O\ dev.$O\ devaudio.$O\ devaudio-$(AUDIO).$O\ devcons.$O\ devdraw.$O\ devfs-$(OS).$O\ devip.$O\ devip-$(OS).$O\ devlfd.$O\ devmnt.$O\ devmouse.$O\ devpipe.$O\ devroot.$O\ devssl.$O\ devtls.$O\ devtab.$O\ error.$O\ parse.$O\ pgrp.$O\ procinit.$O\ rwlock.$O\ sleep.$O\ smalloc.$O\ stub.$O\ sysfile.$O\ sysproc.$O\ qio.$O\ qlock.$O\ term.$O\ uart.$O\ waserror.$O\ $(OS).$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/kern/allocb.c000066400000000000000000000061501314554504700161640ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" enum { Hdrspc = 64, /* leave room for high-level headers */ Bdead = 0x51494F42, /* "QIOB" */ }; struct { Lock lk; ulong bytes; } ialloc; static Block* _allocb(int size) { Block *b; uintptr addr; if((b = mallocz(sizeof(Block)+size+Hdrspc, 0)) == nil) return nil; b->next = nil; b->list = nil; b->free = 0; b->flag = 0; /* align start of data portion by rounding up */ addr = (uintptr)b; addr = ROUND(addr + sizeof(Block), BLOCKALIGN); b->base = (uchar*)addr; /* align end of data portion by rounding down */ b->lim = ((uchar*)b) + sizeof(Block)+size+Hdrspc; addr = (uintptr)(b->lim); addr = addr & ~(BLOCKALIGN-1); b->lim = (uchar*)addr; /* leave sluff at beginning for added headers */ b->rp = b->lim - ROUND(size, BLOCKALIGN); if(b->rp < b->base) panic("_allocb"); b->wp = b->rp; return b; } Block* allocb(int size) { Block *b; /* * Check in a process and wait until successful. * Can still error out of here, though. */ if(up == nil) panic("allocb without up: %p\n", getcallerpc(&size)); if((b = _allocb(size)) == nil){ panic("allocb: no memory for %d bytes\n", size); } setmalloctag(b, getcallerpc(&size)); return b; } Block* iallocb(int size) { Block *b; static int m1, m2; if(ialloc.bytes > conf.ialloc){ if((m1++%10000)==0) print("iallocb: limited %lud/%lud\n", ialloc.bytes, conf.ialloc); return 0; } if((b = _allocb(size)) == nil){ if((m2++%10000)==0) print("iallocb: no memory %lud/%lud\n", ialloc.bytes, conf.ialloc); return nil; } setmalloctag(b, getcallerpc(&size)); b->flag = BINTR; ilock(&ialloc.lk); ialloc.bytes += b->lim - b->base; iunlock(&ialloc.lk); return b; } void freeb(Block *b) { void *dead = (void*)Bdead; if(b == nil) return; /* * drivers which perform non cache coherent DMA manage their own buffer * pool of uncached buffers and provide their own free routine. */ if(b->free) { b->free(b); return; } if(b->flag & BINTR) { ilock(&ialloc.lk); ialloc.bytes -= b->lim - b->base; iunlock(&ialloc.lk); } /* poison the block in case someone is still holding onto it */ b->next = dead; b->rp = dead; b->wp = dead; b->lim = dead; b->base = dead; free(b); } void checkb(Block *b, char *msg) { void *dead = (void*)Bdead; if(b == dead) panic("checkb b %s %lux", msg, b); if(b->base == dead || b->lim == dead || b->next == dead || b->rp == dead || b->wp == dead){ print("checkb: base 0x%8.8luX lim 0x%8.8luX next 0x%8.8luX\n", b->base, b->lim, b->next); print("checkb: rp 0x%8.8luX wp 0x%8.8luX\n", b->rp, b->wp); panic("checkb dead: %s\n", msg); } if(b->base > b->lim) panic("checkb 0 %s %lux %lux", msg, b->base, b->lim); if(b->rp < b->base) panic("checkb 1 %s %lux %lux", msg, b->base, b->rp); if(b->wp < b->base) panic("checkb 2 %s %lux %lux", msg, b->base, b->wp); if(b->rp > b->lim) panic("checkb 3 %s %lux %lux", msg, b->rp, b->lim); if(b->wp > b->lim) panic("checkb 4 %s %lux %lux", msg, b->wp, b->lim); } void iallocsummary(void) { print("ialloc %lud/%lud\n", ialloc.bytes, conf.ialloc); } drawterm-20170818/kern/cache.c000066400000000000000000000007221314554504700157720ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" void cinit(void) { } void copen(Chan *c) { USED(c); } int cread(Chan *c, uchar *buf, int len, vlong off) { USED(c); USED(buf); USED(len); USED(off); return 0; } void cupdate(Chan *c, uchar *buf, int len, vlong off) { USED(c); USED(buf); USED(len); USED(off); } void cwrite(Chan* c, uchar *buf, int len, vlong off) { USED(c); USED(buf); USED(len); USED(off); } drawterm-20170818/kern/chan.c000066400000000000000000000716311314554504700156470ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" int chandebug=0; /* toggled by sysr1 */ QLock chanprint; /* probably asking for trouble (deadlocks) -rsc */ int domount(Chan**, Mhead**); void dumpmount(void) /* DEBUGGING */ { Pgrp *pg; Mount *t; Mhead **h, **he, *f; if(up == nil){ print("no process for dumpmount\n"); return; } pg = up->pgrp; if(pg == nil){ print("no pgrp for dumpmount\n"); return; } rlock(&pg->ns); if(waserror()) { runlock(&pg->ns); nexterror(); } he = &pg->mnthash[MNTHASH]; for(h = pg->mnthash; h < he; h++) { for(f = *h; f; f = f->hash) { print("head: %p: %s 0x%llux.%lud %C %lud -> \n", f, f->from->name->s, f->from->qid.path, f->from->qid.vers, devtab[f->from->type]->dc, f->from->dev); for(t = f->mount; t; t = t->next) print("\t%p: %s (umh %p) (path %.8llux dev %C %lud)\n", t, t->to->name->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev); } } poperror(); runlock(&pg->ns); } char* c2name(Chan *c) /* DEBUGGING */ { if(c == nil) return ""; if(c->name == nil) return ""; if(c->name->s == nil) return ""; return c->name->s; } enum { CNAMESLOP = 20 }; struct { Lock lk; int fid; Chan *free; Chan *list; }chanalloc; typedef struct Elemlist Elemlist; struct Elemlist { char *name; /* copy of name, so '/' can be overwritten */ int nelems; char **elems; int *off; int mustbedir; }; #define SEP(c) ((c) == 0 || (c) == '/') void cleancname(Cname*); int isdotdot(char *p) { return p[0]=='.' && p[1]=='.' && p[2]=='\0'; } int incref(Ref *r) { int x; lock(&r->lk); x = ++r->ref; unlock(&r->lk); return x; } int decref(Ref *r) { int x; lock(&r->lk); x = --r->ref; unlock(&r->lk); if(x < 0) panic("decref, pc=0x%p", getcallerpc(&r)); return x; } /* * Rather than strncpy, which zeros the rest of the buffer, kstrcpy * truncates if necessary, always zero terminates, does not zero fill, * and puts ... at the end of the string if it's too long. Usually used to * save a string in up->genbuf; */ void kstrcpy(char *s, char *t, int ns) { int nt; nt = strlen(t); if(nt+1 <= ns){ memmove(s, t, nt+1); return; } /* too long */ if(ns < 4){ /* but very short! */ strncpy(s, t, ns); return; } /* truncate with ... at character boundary (very rare case) */ memmove(s, t, ns-4); ns -= 4; s[ns] = '\0'; /* look for first byte of UTF-8 sequence by skipping continuation bytes */ while(ns>0 && (s[--ns]&0xC0)==0x80) ; strcpy(s+ns, "..."); } int emptystr(char *s) { if(s == nil) return 1; if(s[0] == '\0') return 1; return 0; } /* * Atomically replace *p with copy of s */ void kstrdup(char **p, char *s) { int n; char *t, *prev; n = strlen(s)+1; /* if it's a user, we can wait for memory; if not, something's very wrong */ if(up){ t = smalloc(n); setmalloctag(t, getcallerpc(&p)); }else{ t = malloc(n); if(t == nil) panic("kstrdup: no memory"); } memmove(t, s, n); prev = *p; *p = t; free(prev); } void chandevreset(void) { int i; for(i=0; devtab[i] != nil; i++) devtab[i]->reset(); } void chandevinit(void) { int i; for(i=0; devtab[i] != nil; i++) devtab[i]->init(); } void chandevshutdown(void) { int i; /* shutdown in reverse order */ for(i=0; devtab[i] != nil; i++) ; for(i--; i >= 0; i--) devtab[i]->shutdown(); } Chan* newchan(void) { Chan *c; lock(&chanalloc.lk); c = chanalloc.free; if(c != 0) chanalloc.free = c->next; unlock(&chanalloc.lk); if(c == nil) { c = smalloc(sizeof(Chan)); lock(&chanalloc.lk); c->fid = ++chanalloc.fid; c->link = chanalloc.list; chanalloc.list = c; unlock(&chanalloc.lk); } /* if you get an error before associating with a dev, close calls rootclose, a nop */ c->type = 0; c->flag = 0; c->ref.ref = 1; c->dev = 0; c->offset = 0; c->iounit = 0; c->umh = 0; c->uri = 0; c->dri = 0; c->aux = 0; c->mchan = 0; c->mcp = 0; c->mux = 0; memset(&c->mqid, 0, sizeof(c->mqid)); c->name = 0; return c; } static Ref ncname; Cname* newcname(char *s) { Cname *n; int i; n = smalloc(sizeof(Cname)); i = strlen(s); n->len = i; n->alen = i+CNAMESLOP; n->s = smalloc(n->alen); memmove(n->s, s, i+1); n->ref.ref = 1; incref(&ncname); return n; } void cnameclose(Cname *n) { if(n == nil) return; if(decref(&n->ref)) return; decref(&ncname); free(n->s); free(n); } Cname* addelem(Cname *n, char *s) { int i, a; char *t; Cname *new; if(s[0]=='.' && s[1]=='\0') return n; if(n->ref.ref > 1){ /* copy on write */ new = newcname(n->s); cnameclose(n); n = new; } i = strlen(s); if(n->len+1+i+1 > n->alen){ a = n->len+1+i+1 + CNAMESLOP; t = smalloc(a); memmove(t, n->s, n->len+1); free(n->s); n->s = t; n->alen = a; } if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/') /* don't insert extra slash if one is present */ n->s[n->len++] = '/'; memmove(n->s+n->len, s, i+1); n->len += i; if(isdotdot(s)) cleancname(n); return n; } void chanfree(Chan *c) { c->flag = CFREE; if(c->umh != nil){ putmhead(c->umh); c->umh = nil; } if(c->umc != nil){ cclose(c->umc); c->umc = nil; } if(c->mux != nil){ muxclose(c->mux); c->mux = nil; } if(c->mchan != nil){ cclose(c->mchan); c->mchan = nil; } cnameclose(c->name); lock(&chanalloc.lk); c->next = chanalloc.free; chanalloc.free = c; unlock(&chanalloc.lk); } void cclose(Chan *c) { if(c->flag&CFREE) panic("cclose %p", getcallerpc(&c)); if(decref(&c->ref)) return; if(!waserror()){ devtab[c->type]->close(c); poperror(); } chanfree(c); } /* * Make sure we have the only copy of c. (Copy on write.) */ Chan* cunique(Chan *c) { Chan *nc; if(c->ref.ref != 1) { nc = cclone(c); cclose(c); c = nc; } return c; } int eqqid(Qid a, Qid b) { return a.path==b.path && a.vers==b.vers; } int eqchan(Chan *a, Chan *b, int pathonly) { if(a->qid.path != b->qid.path) return 0; if(!pathonly && a->qid.vers!=b->qid.vers) return 0; if(a->type != b->type) return 0; if(a->dev != b->dev) return 0; return 1; } int eqchantdqid(Chan *a, int type, int dev, Qid qid, int pathonly) { if(a->qid.path != qid.path) return 0; if(!pathonly && a->qid.vers!=qid.vers) return 0; if(a->type != type) return 0; if(a->dev != dev) return 0; return 1; } Mhead* newmhead(Chan *from) { Mhead *mh; mh = smalloc(sizeof(Mhead)); mh->ref.ref = 1; mh->from = from; incref(&from->ref); /* n = from->name->len; if(n >= sizeof(mh->fromname)) n = sizeof(mh->fromname)-1; memmove(mh->fromname, from->name->s, n); mh->fromname[n] = 0; */ return mh; } int cmount(Chan **newp, Chan *old, int flag, char *spec) { Pgrp *pg; int order, flg; Mhead *m, **l, *mh; Mount *nm, *f, *um, **h; Chan *new; if(QTDIR & (old->qid.type^(*newp)->qid.type)) error(Emount); if(old->umh)print("cmount old extra umh\n"); order = flag&MORDER; if((old->qid.type&QTDIR)==0 && order != MREPL) error(Emount); new = *newp; mh = new->umh; /* * Not allowed to bind when the old directory * is itself a union. (Maybe it should be allowed, but I don't see * what the semantics would be.) * * We need to check mh->mount->next to tell unions apart from * simple mount points, so that things like * mount -c fd /root * bind -c /root / * work. The check of mount->mflag catches things like * mount fd /root * bind -c /root / * * This is far more complicated than it should be, but I don't * see an easier way at the moment. -rsc */ if((flag&MCREATE) && mh && mh->mount && (mh->mount->next || !(mh->mount->mflag&MCREATE))) error(Emount); pg = up->pgrp; wlock(&pg->ns); l = &MOUNTH(pg, old->qid); for(m = *l; m; m = m->hash) { if(eqchan(m->from, old, 1)) break; l = &m->hash; } if(m == nil) { /* * nothing mounted here yet. create a mount * head and add to the hash table. */ m = newmhead(old); *l = m; /* * if this is a union mount, add the old * node to the mount chain. */ if(order != MREPL) m->mount = newmount(m, old, 0, 0); } wlock(&m->lock); if(waserror()){ wunlock(&m->lock); nexterror(); } wunlock(&pg->ns); nm = newmount(m, new, flag, spec); if(mh != nil && mh->mount != nil) { /* * copy a union when binding it onto a directory */ flg = order; if(order == MREPL) flg = MAFTER; h = &nm->next; um = mh->mount; for(um = um->next; um; um = um->next) { f = newmount(m, um->to, flg, um->spec); *h = f; h = &f->next; } } if(m->mount && order == MREPL) { mountfree(m->mount); m->mount = 0; } if(flag & MCREATE) nm->mflag |= MCREATE; if(m->mount && order == MAFTER) { for(f = m->mount; f->next; f = f->next) ; f->next = nm; } else { for(f = nm; f->next; f = f->next) ; f->next = m->mount; m->mount = nm; } wunlock(&m->lock); poperror(); return nm->mountid; } void cunmount(Chan *mnt, Chan *mounted) { Pgrp *pg; Mhead *m, **l; Mount *f, **p; if(mnt->umh) /* should not happen */ print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh); /* * It _can_ happen that mounted->umh is non-nil, * because mounted is the result of namec(Aopen) * (see sysfile.c:/^sysunmount). * If we open a union directory, it will have a umh. * Although surprising, this is okay, since the * cclose will take care of freeing the umh. */ pg = up->pgrp; wlock(&pg->ns); l = &MOUNTH(pg, mnt->qid); for(m = *l; m; m = m->hash) { if(eqchan(m->from, mnt, 1)) break; l = &m->hash; } if(m == 0) { wunlock(&pg->ns); error(Eunmount); } wlock(&m->lock); if(mounted == 0) { *l = m->hash; wunlock(&pg->ns); mountfree(m->mount); m->mount = nil; cclose(m->from); wunlock(&m->lock); putmhead(m); return; } p = &m->mount; for(f = *p; f; f = f->next) { /* BUG: Needs to be 2 pass */ if(eqchan(f->to, mounted, 1) || (f->to->mchan && eqchan(f->to->mchan, mounted, 1))) { *p = f->next; f->next = 0; mountfree(f); if(m->mount == nil) { *l = m->hash; cclose(m->from); wunlock(&m->lock); wunlock(&pg->ns); putmhead(m); return; } wunlock(&m->lock); wunlock(&pg->ns); return; } p = &f->next; } wunlock(&m->lock); wunlock(&pg->ns); error(Eunion); } Chan* cclone(Chan *c) { Chan *nc; Walkqid *wq; wq = devtab[c->type]->walk(c, nil, nil, 0); if(wq == nil) error("clone failed"); nc = wq->clone; free(wq); nc->name = c->name; if(c->name) incref(&c->name->ref); return nc; } int findmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid) { Pgrp *pg; Mhead *m; pg = up->pgrp; rlock(&pg->ns); for(m = MOUNTH(pg, qid); m; m = m->hash){ rlock(&m->lock); if(m->from == nil){ print("m %p m->from 0\n", m); runlock(&m->lock); continue; } if(eqchantdqid(m->from, type, dev, qid, 1)) { runlock(&pg->ns); if(mp != nil){ incref(&m->ref); if(*mp != nil) putmhead(*mp); *mp = m; } if(*cp != nil) cclose(*cp); incref(&m->mount->to->ref); *cp = m->mount->to; runlock(&m->lock); return 1; } runlock(&m->lock); } runlock(&pg->ns); return 0; } int domount(Chan **cp, Mhead **mp) { return findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid); } Chan* undomount(Chan *c, Cname *name) { Chan *nc; Pgrp *pg; Mount *t; Mhead **h, **he, *f; pg = up->pgrp; rlock(&pg->ns); if(waserror()) { runlock(&pg->ns); nexterror(); } he = &pg->mnthash[MNTHASH]; for(h = pg->mnthash; h < he; h++) { for(f = *h; f; f = f->hash) { if(strcmp(f->from->name->s, name->s) != 0) continue; for(t = f->mount; t; t = t->next) { if(eqchan(c, t->to, 1)) { /* * We want to come out on the left hand side of the mount * point using the element of the union that we entered on. * To do this, find the element that has a from name of * c->name->s. */ if(strcmp(t->head->from->name->s, name->s) != 0) continue; nc = t->head->from; incref(&nc->ref); cclose(c); c = nc; break; } } } } poperror(); runlock(&pg->ns); return c; } /* * Either walks all the way or not at all. No partial results in *cp. * *nerror is the number of names to display in an error message. */ static char Edoesnotexist[] = "does not exist"; int walk(Chan **cp, char **names, int nnames, int nomount, int *nerror) { int dev, dotdot, i, n, nhave, ntry, type; Chan *c, *nc; Cname *cname; Mount *f; Mhead *mh, *nmh; Walkqid *wq; c = *cp; incref(&c->ref); cname = c->name; incref(&cname->ref); mh = nil; /* * While we haven't gotten all the way down the path: * 1. step through a mount point, if any * 2. send a walk request for initial dotdot or initial prefix without dotdot * 3. move to the first mountpoint along the way. * 4. repeat. * * An invariant is that each time through the loop, c is on the undomount * side of the mount point, and c's name is cname. */ for(nhave=0; nhaveqid.type&QTDIR)==0){ if(nerror) *nerror = nhave; cnameclose(cname); cclose(c); strcpy(up->errstr, Enotdir); if(mh != nil) {print("walk 1\n"); putmhead(mh); } return -1; } ntry = nnames - nhave; if(ntry > MAXWELEM) ntry = MAXWELEM; dotdot = 0; for(i=0; itype; dev = c->dev; if((wq = devtab[type]->walk(c, nil, names+nhave, ntry)) == nil){ /* try a union mount, if any */ if(mh && !nomount){ /* * mh->mount == c, so start at mh->mount->next */ rlock(&mh->lock); for(f = mh->mount->next; f; f = f->next) if((wq = devtab[f->to->type]->walk(f->to, nil, names+nhave, ntry)) != nil) break; runlock(&mh->lock); if(f != nil){ type = f->to->type; dev = f->to->dev; } } if(wq == nil){ cclose(c); cnameclose(cname); if(nerror) *nerror = nhave+1; if(mh != nil) putmhead(mh); return -1; } } nmh = nil; if(dotdot) { assert(wq->nqid == 1); assert(wq->clone != nil); cname = addelem(cname, ".."); nc = undomount(wq->clone, cname); n = 1; } else { nc = nil; if(!nomount) for(i=0; inqid && iqid[i])) break; if(nc == nil){ /* no mount points along path */ if(wq->clone == nil){ cclose(c); cnameclose(cname); if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){ if(nerror) *nerror = nhave+wq->nqid+1; strcpy(up->errstr, Edoesnotexist); }else{ if(nerror) *nerror = nhave+wq->nqid; strcpy(up->errstr, Enotdir); } free(wq); if(mh != nil) putmhead(mh); return -1; } n = wq->nqid; nc = wq->clone; }else{ /* stopped early, at a mount point */ if(wq->clone != nil){ cclose(wq->clone); wq->clone = nil; } n = i+1; } for(i=0; iumh != nil){ //BUG print("walk umh\n"); putmhead(c->umh); c->umh = nil; } cnameclose(c->name); c->name = cname; cclose(*cp); *cp = c; if(nerror) *nerror = 0; return 0; } /* * c is a mounted non-creatable directory. find a creatable one. */ Chan* createdir(Chan *c, Mhead *m) { Chan *nc; Mount *f; rlock(&m->lock); if(waserror()) { runlock(&m->lock); nexterror(); } for(f = m->mount; f; f = f->next) { if(f->mflag&MCREATE) { nc = cclone(f->to); runlock(&m->lock); poperror(); cclose(c); return nc; } } error(Enocreate); return 0; } void saveregisters(void) { } /* * In place, rewrite name to compress multiple /, eliminate ., and process .. */ void cleancname(Cname *n) { char *p; if(n->s[0] == '#'){ p = strchr(n->s, '/'); if(p == nil) return; cleanname(p); /* * The correct name is #i rather than #i/, * but the correct name of #/ is #/. */ if(strcmp(p, "/")==0 && n->s[1] != '/') *p = '\0'; }else cleanname(n->s); n->len = strlen(n->s); } static void growparse(Elemlist *e) { char **new; int *inew; enum { Delta = 8 }; if(e->nelems % Delta == 0){ new = smalloc((e->nelems+Delta) * sizeof(char*)); memmove(new, e->elems, e->nelems*sizeof(char*)); free(e->elems); e->elems = new; inew = smalloc((e->nelems+Delta+1) * sizeof(int)); memmove(inew, e->off, e->nelems*sizeof(int)); free(e->off); e->off = inew; } } /* * The name is known to be valid. * Copy the name so slashes can be overwritten. * An empty string will set nelem=0. * A path ending in / or /. or /.//./ etc. will have * e.mustbedir = 1, so that we correctly * reject, e.g., "/adm/users/." when /adm/users is a file * rather than a directory. */ static void parsename(char *name, Elemlist *e) { char *slash; kstrdup(&e->name, name); name = e->name; e->nelems = 0; e->elems = nil; e->off = smalloc(sizeof(int)); e->off[0] = skipslash(name) - name; for(;;){ name = skipslash(name); if(*name=='\0'){ e->mustbedir = 1; break; } growparse(e); e->elems[e->nelems++] = name; slash = utfrune(name, '/'); if(slash == nil){ e->off[e->nelems] = name+strlen(name) - e->name; e->mustbedir = 0; break; } e->off[e->nelems] = slash - e->name; *slash++ = '\0'; name = slash; } } void* mymemrchr(void *va, int c, long n) { uchar *a, *e; a = va; for(e=a+n-1; e>a; e--) if(*e == c) return e; return nil; } /* * Turn a name into a channel. * &name[0] is known to be a valid address. It may be a kernel address. * * Opening with amode Aopen, Acreate, or Aremove guarantees * that the result will be the only reference to that particular fid. * This is necessary since we might pass the result to * devtab[]->remove(). * * Opening Atodir, Amount, or Aaccess does not guarantee this. * * Opening Aaccess can, under certain conditions, return a * correct Chan* but with an incorrect Cname attached. * Since the functions that open Aaccess (sysstat, syswstat, sys_stat) * do not use the Cname*, this avoids an unnecessary clone. */ Chan* namec(char *aname, int amode, int omode, ulong perm) { int n, prefix, len, t, nomount, npath; Chan *c, *cnew; Cname *cname; Elemlist e; Rune r; Mhead *m; char *createerr, tmperrbuf[ERRMAX]; char *name; name = aname; if(name[0] == '\0') error("empty file name"); validname(name, 1); /* * Find the starting off point (the current slash, the root of * a device tree, or the current dot) as well as the name to * evaluate starting there. */ nomount = 0; switch(name[0]){ case '/': c = up->slash; incref(&c->ref); break; case '#': nomount = 1; up->genbuf[0] = '\0'; n = 0; while(*name!='\0' && (*name != '/' || n < 2)){ if(n >= sizeof(up->genbuf)-1) error(Efilename); up->genbuf[n++] = *name++; } up->genbuf[n] = '\0'; /* * noattach is sandboxing. * * the OK exceptions are: * | it only gives access to pipes you create * d this process's file descriptors * e this process's environment * the iffy exceptions are: * c time and pid, but also cons and consctl * p control of your own processes (and unfortunately * any others left unprotected) */ n = chartorune(&r, up->genbuf+1)+1; /* actually / is caught by parsing earlier */ if(utfrune("M", r)) error(Enoattach); if(up->pgrp->noattach && utfrune("|decp", r)==nil) error(Enoattach); t = devno(r, 1); if(t == -1) error(Ebadsharp); c = devtab[t]->attach(up->genbuf+n); break; default: c = up->dot; incref(&c->ref); break; } prefix = name - aname; e.name = nil; e.elems = nil; e.off = nil; e.nelems = 0; if(waserror()){ cclose(c); free(e.name); free(e.elems); free(e.off); //dumpmount(); nexterror(); } /* * Build a list of elements in the path. */ parsename(name, &e); /* * On create, .... */ if(amode == Acreate){ /* perm must have DMDIR if last element is / or /. */ if(e.mustbedir && !(perm&DMDIR)){ npath = e.nelems; strcpy(tmperrbuf, "create without DMDIR"); goto NameError; } /* don't try to walk the last path element just yet. */ if(e.nelems == 0) error(Eexist); e.nelems--; } if(walk(&c, e.elems, e.nelems, nomount, &npath) < 0){ if(npath < 0 || npath > e.nelems){ print("namec %s walk error npath=%d\n", aname, npath); nexterror(); } strcpy(tmperrbuf, up->errstr); NameError: len = prefix+e.off[npath]; if(len < ERRMAX/3 || (name=mymemrchr(aname, '/', len))==nil || name==aname) snprint(up->genbuf, sizeof up->genbuf, "%.*s", len, aname); else snprint(up->genbuf, sizeof up->genbuf, "...%.*s", (int)(len-(name-aname)), name); snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, tmperrbuf); nexterror(); } if(e.mustbedir && !(c->qid.type&QTDIR)){ npath = e.nelems; strcpy(tmperrbuf, "not a directory"); goto NameError; } if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR)){ npath = e.nelems; error("cannot exec directory"); } switch(amode){ case Aaccess: if(!nomount) domount(&c, nil); break; case Abind: m = nil; if(!nomount) domount(&c, &m); if(c->umh != nil) putmhead(c->umh); c->umh = m; break; case Aremove: case Aopen: Open: /* save the name; domount might change c */ cname = c->name; incref(&cname->ref); m = nil; if(!nomount) domount(&c, &m); /* our own copy to open or remove */ c = cunique(c); /* now it's our copy anyway, we can put the name back */ cnameclose(c->name); c->name = cname; switch(amode){ case Aremove: putmhead(m); break; case Aopen: case Acreate: if(c->umh != nil){ print("cunique umh Open\n"); putmhead(c->umh); c->umh = nil; } /* only save the mount head if it's a multiple element union */ if(m && m->mount && m->mount->next) c->umh = m; else putmhead(m); /* save registers else error() in open has wrong value of c saved */ saveregisters(); if(omode == OEXEC) c->flag &= ~CCACHE; c = devtab[c->type]->open(c, omode&~OCEXEC); if(omode & OCEXEC) c->flag |= CCEXEC; if(omode & ORCLOSE) c->flag |= CRCLOSE; break; } break; case Atodir: /* * Directories (e.g. for cd) are left before the mount point, * so one may mount on / or . and see the effect. */ if(!(c->qid.type & QTDIR)) error(Enotdir); break; case Amount: /* * When mounting on an already mounted upon directory, * one wants subsequent mounts to be attached to the * original directory, not the replacement. Don't domount. */ break; case Acreate: /* * We've already walked all but the last element. * If the last exists, try to open it OTRUNC. * If omode&OEXCL is set, just give up. */ e.nelems++; if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){ if(omode&OEXCL) error(Eexist); omode |= OTRUNC; goto Open; } /* * The semantics of the create(2) system call are that if the * file exists and can be written, it is to be opened with truncation. * On the other hand, the create(5) message fails if the file exists. * If we get two create(2) calls happening simultaneously, * they might both get here and send create(5) messages, but only * one of the messages will succeed. To provide the expected create(2) * semantics, the call with the failed message needs to try the above * walk again, opening for truncation. This correctly solves the * create/create race, in the sense that any observable outcome can * be explained as one happening before the other. * The create/create race is quite common. For example, it happens * when two rc subshells simultaneously update the same * environment variable. * * The implementation still admits a create/create/remove race: * (A) walk to file, fails * (B) walk to file, fails * (A) create file, succeeds, returns * (B) create file, fails * (A) remove file, succeeds, returns * (B) walk to file, return failure. * * This is hardly as common as the create/create race, and is really * not too much worse than what might happen if (B) got a hold of a * file descriptor and then the file was removed -- either way (B) can't do * anything with the result of the create call. So we don't care about this race. * * Applications that care about more fine-grained decision of the races * can use the OEXCL flag to get at the underlying create(5) semantics; * by default we provide the common case. * * We need to stay behind the mount point in case we * need to do the first walk again (should the create fail). * * We also need to cross the mount point and find the directory * in the union in which we should be creating. * * The channel staying behind is c, the one moving forward is cnew. */ m = nil; cnew = nil; /* is this assignment necessary? */ if(!waserror()){ /* try create */ if(!nomount && findmount(&cnew, &m, c->type, c->dev, c->qid)) cnew = createdir(cnew, m); else{ cnew = c; incref(&cnew->ref); } /* * We need our own copy of the Chan because we're * about to send a create, which will move it. Once we have * our own copy, we can fix the name, which might be wrong * if findmount gave us a new Chan. */ cnew = cunique(cnew); cnameclose(cnew->name); cnew->name = c->name; incref(&cnew->name->ref); devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm); poperror(); if(omode & OCEXEC) cnew->flag |= CCEXEC; if(omode & ORCLOSE) cnew->flag |= CRCLOSE; if(m) putmhead(m); cclose(c); c = cnew; c->name = addelem(c->name, e.elems[e.nelems-1]); break; }else{ /* create failed */ cclose(cnew); if(m) putmhead(m); if(omode & OEXCL) nexterror(); /* save error */ createerr = up->errstr; up->errstr = tmperrbuf; /* note: we depend that walk does not error */ if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){ up->errstr = createerr; error(createerr); /* report true error */ } up->errstr = createerr; omode |= OTRUNC; goto Open; } panic("namec: not reached"); default: panic("unknown namec access %d\n", amode); } poperror(); /* place final element in genbuf for e.g. exec */ if(e.nelems > 0) kstrcpy(up->genbuf, e.elems[e.nelems-1], sizeof up->genbuf); else kstrcpy(up->genbuf, ".", sizeof up->genbuf); free(e.name); free(e.elems); free(e.off); return c; } /* * name is valid. skip leading / and ./ as much as possible */ char* skipslash(char *name) { while(name[0]=='/' || (name[0]=='.' && (name[1]==0 || name[1]=='/'))) name++; return name; } char isfrog[256]={ /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */ /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x08 */ /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 */ /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x18 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 1, /* 0x28 (1 is '/', 0x2F) */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 1, /* 0x78 (1 is DEL, 0x7F) */ }; /* * Check that the name * a) is in valid memory. * b) is shorter than 2^16 bytes, so it can fit in a 9P string field. * c) contains no frogs. * The first byte is known to be addressible by the requester, so the * routine works for kernel and user memory both. * The parameter slashok flags whether a slash character is an error * or a valid character. */ void validname(char *aname, int slashok) { char *ename, *name; int c; Rune r; name = aname; /* if(((ulong)name & KZERO) != KZERO) { p = name; t = BY2PG-((ulong)p&(BY2PG-1)); while((ename=vmemchr(p, 0, t)) == nil) { p += t; t = BY2PG; } }else */ ename = memchr(name, 0, (1<<16)); if(ename==nil || ename-name>=(1<<16)) error("name too long"); while(*name){ /* all characters above '~' are ok */ c = *(uchar*)name; if(c >= Runeself) name += chartorune(&r, name); else{ if(isfrog[c]) if(!slashok || c!='/'){ snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname); error(up->genbuf); } name++; } } } void isdir(Chan *c) { if(c->qid.type & QTDIR) return; error(Enotdir); } /* * This is necessary because there are many * pointers to the top of a given mount list: * * - the mhead in the namespace hash table * - the mhead in chans returned from findmount: * used in namec and then by unionread. * - the mhead in chans returned from createdir: * used in the open/create race protect, which is gone. * * The RWlock in the Mhead protects the mount list it contains. * The mount list is deleted when we cunmount. * The RWlock ensures that nothing is using the mount list at that time. * * It is okay to replace c->mh with whatever you want as * long as you are sure you have a unique reference to it. * * This comment might belong somewhere else. */ void putmhead(Mhead *m) { if(m && decref(&m->ref) == 0){ m->mount = (Mount*)0xCafeBeef; free(m); } } drawterm-20170818/kern/dat.h000066400000000000000000000247351314554504700155160ustar00rootroot00000000000000#define KNAMELEN 28 /* max length of name held in kernel */ #define DOMLEN 64 #define BLOCKALIGN 8 typedef struct Alarms Alarms; typedef struct Block Block; typedef struct CSN CSN; typedef struct Chan Chan; typedef struct Cmdbuf Cmdbuf; typedef struct Cmdtab Cmdtab; typedef struct Cname Cname; typedef struct Conf Conf; typedef struct Dev Dev; typedef struct Dirtab Dirtab; typedef struct Edfinterface Edfinterface; typedef struct Egrp Egrp; typedef struct Evalue Evalue; typedef struct Fgrp Fgrp; typedef struct FPsave FPsave; typedef struct DevConf DevConf; typedef struct Label Label; typedef struct List List; typedef struct Log Log; typedef struct Logflag Logflag; typedef struct Mntcache Mntcache; typedef struct Mount Mount; typedef struct Mntrpc Mntrpc; typedef struct Mntwalk Mntwalk; typedef struct Mnt Mnt; typedef struct Mhead Mhead; typedef struct Note Note; typedef struct Page Page; typedef struct Palloc Palloc; typedef struct Perf Perf; typedef struct Pgrps Pgrps; typedef struct PhysUart PhysUart; typedef struct Pgrp Pgrp; typedef struct Physseg Physseg; typedef struct Proc Proc; typedef struct Pte Pte; typedef struct Pthash Pthash; typedef struct Queue Queue; typedef struct Ref Ref; typedef struct Rendez Rendez; typedef struct Rgrp Rgrp; typedef struct RWlock RWlock; typedef struct Schedq Schedq; typedef struct Segment Segment; typedef struct Session Session; typedef struct Task Task; typedef struct Talarm Talarm; typedef struct Timer Timer; typedef struct Uart Uart; typedef struct Ureg Ureg; typedef struct Waitq Waitq; typedef struct Walkqid Walkqid; typedef int Devgen(Chan*, char*, Dirtab*, int, int, Dir*); #include "fcall.h" enum { SnarfSize = 64*1024, }; struct Conf { ulong nmach; /* processors */ ulong nproc; /* processes */ ulong monitor; /* has monitor? */ ulong npage0; /* total physical pages of memory */ ulong npage1; /* total physical pages of memory */ ulong npage; /* total physical pages of memory */ ulong upages; /* user page pool */ ulong nimage; /* number of page cache image headers */ ulong nswap; /* number of swap pages */ int nswppo; /* max # of pageouts per segment pass */ ulong base0; /* base of bank 0 */ ulong base1; /* base of bank 1 */ ulong copymode; /* 0 is copy on write, 1 is copy on reference */ ulong ialloc; /* max interrupt time allocation in bytes */ ulong pipeqsize; /* size in bytes of pipe queues */ int nuart; /* number of uart devices */ }; struct Label { jmp_buf buf; }; struct Ref { Lock lk; long ref; }; struct Rendez { Lock lk; Proc *p; }; struct RWlock /* changed from kernel */ { int readers; Lock lk; QLock x; QLock k; }; struct Talarm { Lock lk; Proc *list; }; struct Alarms { QLock lk; Proc *head; }; /* * Access types in namec & channel flags */ enum { Aaccess, /* as in stat, wstat */ Abind, /* for left-hand-side of bind */ Atodir, /* as in chdir */ Aopen, /* for i/o */ Amount, /* to be mounted or mounted upon */ Acreate, /* is to be created */ Aremove, /* will be removed by caller */ COPEN = 0x0001, /* for i/o */ CMSG = 0x0002, /* the message channel for a mount */ /* CCREATE = 0x0004, permits creation if c->mnt */ CCEXEC = 0x0008, /* close on exec */ CFREE = 0x0010, /* not in use */ CRCLOSE = 0x0020, /* remove on close */ CCACHE = 0x0080, /* client cache */ }; /* flag values */ enum { BINTR = (1<<0), BFREE = (1<<1), Bipck = (1<<2), /* ip checksum */ Budpck = (1<<3), /* udp checksum */ Btcpck = (1<<4), /* tcp checksum */ Bpktck = (1<<5), /* packet checksum */ }; struct Block { Block* next; Block* list; uchar* rp; /* first unconsumed byte */ uchar* wp; /* first empty byte */ uchar* lim; /* 1 past the end of the buffer */ uchar* base; /* start of the buffer */ void (*free)(Block*); ushort flag; ushort checksum; /* IP checksum of complete packet (minus media header) */ }; #define BLEN(s) ((s)->wp - (s)->rp) #define BALLOC(s) ((s)->lim - (s)->base) struct Chan { Ref ref; Chan* next; /* allocation */ Chan* link; vlong offset; /* in file */ ushort type; ulong dev; ushort mode; /* read/write */ ushort flag; Qid qid; int fid; /* for devmnt */ ulong iounit; /* chunk size for i/o; 0==default */ Mhead* umh; /* mount point that derived Chan; used in unionread */ Chan* umc; /* channel in union; held for union read */ QLock umqlock; /* serialize unionreads */ int uri; /* union read index */ int dri; /* devdirread index */ ulong mountid; Mntcache *mcp; /* Mount cache pointer */ Mnt *mux; /* Mnt for clients using me for messages */ void* aux; Qid pgrpid; /* for #p/notepg */ ulong mid; /* for ns in devproc */ Chan* mchan; /* channel to mounted server */ Qid mqid; /* qid of root of mount point */ Session*session; Cname *name; }; struct Cname { Ref ref; int alen; /* allocated length */ int len; /* strlen(s) */ char *s; }; struct Dev { int dc; char* name; void (*reset)(void); void (*init)(void); void (*shutdown)(void); Chan* (*attach)(char*); Walkqid* (*walk)(Chan*, Chan*, char**, int); int (*stat)(Chan*, uchar*, int); Chan* (*open)(Chan*, int); void (*create)(Chan*, char*, int, ulong); void (*close)(Chan*); long (*read)(Chan*, void*, long, vlong); Block* (*bread)(Chan*, long, ulong); long (*write)(Chan*, void*, long, vlong); long (*bwrite)(Chan*, Block*, ulong); void (*remove)(Chan*); int (*wstat)(Chan*, uchar*, int); void (*power)(int); /* power mgt: power(1) => on, power (0) => off */ int (*config)(int, char*, DevConf*); // returns nil on error }; struct Dirtab { char name[KNAMELEN]; Qid qid; vlong length; ulong perm; }; struct Walkqid { Chan *clone; int nqid; Qid qid[1]; }; enum { NSMAX = 1000, NSLOG = 7, NSCACHE = (1<ref; channels on this mount point incref(c->mchan) == Mnt.c */ Chan *c; /* Channel to file service */ Proc *rip; /* Reader in progress */ Mntrpc *queue; /* Queue of pending requests on this channel */ ulong id; /* Multiplexer id for channel check */ Mnt *list; /* Free list */ int flags; /* cache */ int msize; /* data + IOHDRSZ */ char *version; /* 9P version */ Queue *q; /* input queue */ }; enum { NUser, /* note provided externally */ NExit, /* deliver note quietly */ NDebug, /* print debug message */ }; struct Note { char msg[ERRMAX]; int flag; /* whether system posted it */ }; enum { RENDLOG = 5, RENDHASH = 1<rendhash[(s)&((1<mnthash[(qid).path&((1< variadic */ }; /* queue state bits, Qmsg, Qcoalesce, and Qkick can be set in qopen */ enum { /* Queue.state */ Qstarve = (1<<0), /* consumer starved */ Qmsg = (1<<1), /* message stream */ Qclosed = (1<<2), /* queue has been closed/hungup */ Qflow = (1<<3), /* producer flow controlled */ Qcoalesce = (1<<4), /* coallesce packets on read */ Qkick = (1<<5), /* always call the kick routine after qwrite */ }; #define DEVDOTDOT -1 extern Proc *_getproc(void); extern void _setproc(Proc*); #define up (_getproc()) drawterm-20170818/kern/data.c000066400000000000000000000006471314554504700156460ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" Proc *up; Conf conf = { 1, 100, 0, 1024*1024*1024, 1024*1024*1024, 1024*1024*1024, 1024*1024*1024, 1024*1024*1024, 1024*1024*1024, 1024*1024*1024, 1024*1024*1024, 1024*1024*1024, 1024*1024*1024, 1024*1024*1024, 1024*1024*1024, 0, }; char *eve = "eve"; ulong kerndate; int cpuserver; char hostdomain[] = "drawterm.net"; drawterm-20170818/kern/dev.c000066400000000000000000000205131314554504700155050ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" extern ulong kerndate; void mkqid(Qid *q, vlong path, ulong vers, int type) { q->type = type; q->vers = vers; q->path = path; } int devno(int c, int user) { int i; for(i = 0; devtab[i] != nil; i++) { if(devtab[i]->dc == c) return i; } if(user == 0) panic("devno %C 0x%ux", c, c); return -1; } void devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db) { db->name = n; if(c->flag&CMSG) qid.type |= QTMOUNT; db->qid = qid; db->type = devtab[c->type]->dc; db->dev = c->dev; db->mode = perm; db->mode |= qid.type << 24; db->atime = seconds(); db->mtime = kerndate; db->length = length; db->uid = user; db->gid = eve; db->muid = user; } /* * (here, Devgen is the prototype; devgen is the function in dev.c.) * * a Devgen is expected to return the directory entry for ".." * if you pass it s==DEVDOTDOT (-1). otherwise... * * there are two contradictory rules. * * (i) if c is a directory, a Devgen is expected to list its children * as you iterate s. * * (ii) whether or not c is a directory, a Devgen is expected to list * its siblings as you iterate s. * * devgen always returns the list of children in the root * directory. thus it follows (i) when c is the root and (ii) otherwise. * many other Devgens follow (i) when c is a directory and (ii) otherwise. * * devwalk assumes (i). it knows that devgen breaks (i) * for children that are themselves directories, and explicitly catches them. * * devstat assumes (ii). if the Devgen in question follows (i) * for this particular c, devstat will not find the necessary info. * with our particular Devgen functions, this happens only for * directories, so devstat makes something up, assuming * c->name, c->qid, eve, DMDIR|0555. * * devdirread assumes (i). the callers have to make sure * that the Devgen satisfies (i) for the chan being read. */ /* * the zeroth element of the table MUST be the directory itself for .. */ int devgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp) { if(tab == 0) return -1; if(i == DEVDOTDOT){ /* nothing */ }else if(name){ for(i=1; i= ntab) return -1; tab += i; } devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp); return 1; } void devreset(void) { } void devinit(void) { } void devshutdown(void) { } Chan* devattach(int tc, char *spec) { Chan *c; char *buf; c = newchan(); mkqid(&c->qid, 0, 0, QTDIR); c->type = devno(tc, 0); if(spec == nil) spec = ""; buf = smalloc(4+strlen(spec)+1); sprint(buf, "#%C%s", tc, spec); c->name = newcname(buf); free(buf); return c; } Chan* devclone(Chan *c) { Chan *nc; if(c->flag & COPEN) panic("clone of open file type %C\n", devtab[c->type]->dc); nc = newchan(); nc->type = c->type; nc->dev = c->dev; nc->mode = c->mode; nc->qid = c->qid; nc->offset = c->offset; nc->umh = nil; nc->mountid = c->mountid; nc->aux = c->aux; nc->pgrpid = c->pgrpid; nc->mid = c->mid; nc->mqid = c->mqid; nc->mcp = c->mcp; return nc; } Walkqid* devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen) { int i, j, alloc; Walkqid *wq; char *n; Dir dir; if(nname > 0) isdir(c); alloc = 0; wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); if(waserror()){ if(alloc && wq->clone!=nil) cclose(wq->clone); free(wq); return nil; } if(nc == nil){ nc = devclone(c); nc->type = 0; /* device doesn't know about this channel yet */ alloc = 1; } wq->clone = nc; for(j=0; jqid.type&QTDIR)){ if(j==0) error(Enotdir); goto Done; } n = name[j]; if(strcmp(n, ".") == 0){ Accept: wq->qid[wq->nqid++] = nc->qid; continue; } if(strcmp(n, "..") == 0){ if((*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir) != 1){ print("devgen walk .. in dev%s %llux broken\n", devtab[nc->type]->name, nc->qid.path); error("broken devgen"); } nc->qid = dir.qid; goto Accept; } /* * Ugly problem: If we're using devgen, make sure we're * walking the directory itself, represented by the first * entry in the table, and not trying to step into a sub- * directory of the table, e.g. /net/net. Devgen itself * should take care of the problem, but it doesn't have * the necessary information (that we're doing a walk). */ if(gen==devgen && nc->qid.path!=tab[0].qid.path) goto Notfound; for(i=0;; i++) { switch((*gen)(nc, n, tab, ntab, i, &dir)){ case -1: Notfound: if(j == 0) error(Enonexist); kstrcpy(up->errstr, Enonexist, ERRMAX); goto Done; case 0: continue; case 1: if(strcmp(n, dir.name) == 0){ nc->qid = dir.qid; goto Accept; } continue; } } } /* * We processed at least one name, so will return some data. * If we didn't process all nname entries succesfully, we drop * the cloned channel and return just the Qids of the walks. */ Done: poperror(); if(wq->nqid < nname){ if(alloc) cclose(wq->clone); wq->clone = nil; }else if(wq->clone){ /* attach cloned channel to same device */ wq->clone->type = c->type; } return wq; } int devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen) { int i; Dir dir; char *p, *elem; for(i=0;; i++) switch((*gen)(c, nil, tab, ntab, i, &dir)){ case -1: if(c->qid.type & QTDIR){ if(c->name == nil) elem = "???"; else if(strcmp(c->name->s, "/") == 0) elem = "/"; else for(elem=p=c->name->s; *p; p++) if(*p == '/') elem = p+1; devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir); n = convD2M(&dir, db, n); if(n == 0) error(Ebadarg); return n; } print("devstat %C %llux\n", devtab[c->type]->dc, c->qid.path); error(Enonexist); case 0: break; case 1: if(c->qid.path == dir.qid.path) { if(c->flag&CMSG) dir.mode |= DMMOUNT; n = convD2M(&dir, db, n); if(n == 0) error(Ebadarg); return n; } break; } error(Egreg); /* not reached? */ return -1; } long devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen) { long m, dsz; struct{ Dir d; char slop[100]; }dir; for(m=0; mdri++) { switch((*gen)(c, nil, tab, ntab, c->dri, &dir.d)){ case -1: return m; case 0: break; case 1: dsz = convD2M(&dir.d, (uchar*)d, n-m); if(dsz <= BIT16SZ){ /* <= not < because this isn't stat; read is stuck */ if(m == 0) error(Eshort); return m; } m += dsz; d += dsz; break; } } return m; } /* * error(Eperm) if open permission not granted for up->user. */ void devpermcheck(char *fileuid, ulong perm, int omode) { ulong t; static int access[] = { 0400, 0200, 0600, 0100 }; if(strcmp(up->user, fileuid) == 0) perm <<= 0; else if(strcmp(up->user, eve) == 0) perm <<= 3; else perm <<= 6; t = access[omode&3]; if((t&perm) != t) error(Eperm); } Chan* devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen) { int i; Dir dir; for(i=0;; i++) { switch((*gen)(c, nil, tab, ntab, i, &dir)){ case -1: goto Return; case 0: break; case 1: if(c->qid.path == dir.qid.path) { devpermcheck(dir.uid, dir.mode, omode); goto Return; } break; } } Return: c->offset = 0; if((c->qid.type&QTDIR) && omode!=OREAD) error(Eperm); c->mode = openmode(omode); c->flag |= COPEN; return c; } void devcreate(Chan *c, char *name, int mode, ulong perm) { USED(c); USED(name); USED(mode); USED(perm); error(Eperm); } Block* devbread(Chan *c, long n, ulong offset) { Block *bp; bp = allocb(n); if(bp == 0) error(Enomem); if(waserror()) { freeb(bp); nexterror(); } bp->wp += devtab[c->type]->read(c, bp->wp, n, offset); poperror(); return bp; } long devbwrite(Chan *c, Block *bp, ulong offset) { long n; if(waserror()) { freeb(bp); nexterror(); } n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset); poperror(); freeb(bp); return n; } void devremove(Chan *c) { USED(c); error(Eperm); } int devwstat(Chan *c, uchar *a, int n) { USED(c); USED(a); USED(n); error(Eperm); return 0; } void devpower(int a) { USED(a); error(Eperm); } int devconfig(int a, char *b, DevConf *c) { USED(a); USED(b); USED(c); error(Eperm); return 0; } drawterm-20170818/kern/devaudio-none.c000066400000000000000000000011641314554504700174650ustar00rootroot00000000000000/* * Linux and BSD */ #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "devaudio.h" /* maybe this should return -1 instead of sysfatal */ void audiodevopen(void) { error("no audio support"); } void audiodevclose(void) { error("no audio support"); } int audiodevread(void *a, int n) { error("no audio support"); return -1; } int audiodevwrite(void *a, int n) { error("no audio support"); return -1; } void audiodevsetvol(int what, int left, int right) { error("no audio support"); } void audiodevgetvol(int what, int *left, int *right) { error("no audio support"); } drawterm-20170818/kern/devaudio-sun.c000066400000000000000000000112671314554504700173400ustar00rootroot00000000000000/* * Sun */ #include #include #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "devaudio.h" enum { Channels = 2, Rate = 44100, Bits = 16, }; static char* afn = 0; static char* cfn = 0; static int afd = -1; static int cfd = -1; static int speed = Rate; static int needswap = -1; static void audiodevinit(void) { uchar *p; ushort leorder; if ((afn = getenv("AUDIODEV")) == nil) afn = "/dev/audio"; cfn = (char*)malloc(strlen(afn) + 3 + 1); if(cfn == nil) panic("out of memory"); strcpy(cfn, afn); strcat(cfn, "ctl"); /* * Plan 9 /dev/audio is always little endian; * solaris /dev/audio seems to expect native byte order, * so on big endian machine (like sparc) we have to swap. */ leorder = (ushort) 0x0100; p = (uchar*)&leorder; if (p[0] == 0 && p[1] == 1) { /* little-endian: nothing to do */ needswap = 0; } else { /* big-endian: translate Plan 9 little-endian */ needswap = 1; } } /* maybe this should return -1 instead of sysfatal */ void audiodevopen(void) { audio_info_t info; struct audio_device ad; if (afn == nil || cfn == nil) audiodevinit(); if((afd = open(afn, O_WRONLY)) < 0) goto err; if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0) goto err; AUDIO_INITINFO(&info); info.play.precision = Bits; info.play.channels = Channels; info.play.sample_rate = speed; info.play.encoding = AUDIO_ENCODING_LINEAR; if(ioctl(afd, AUDIO_SETINFO, &info) < 0) goto err; return; err: if(afd >= 0) close(afd); afd = -1; if(cfd >= 0) close(cfd); cfd = -1; oserror(); } void audiodevclose(void) { if(afd >= 0) close(afd); if(cfd >= 0) close(cfd); afd = -1; cfd = -1; } static double fromsun(double val, double min, double max) { return (val-min) / (max-min); } static double tosun(double val, double min, double max) { return val*(max-min) + min; } static void setvolbal(double left, double right) { audio_info_t info; double vol, bal; if (left < 0 || right < 0) { /* should not happen */ return; } else if (left == right) { vol = tosun(left/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN); bal = AUDIO_MID_BALANCE; } else if (left < right) { vol = tosun(right/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN); bal = tosun(1.0 - left/right, AUDIO_MID_BALANCE, AUDIO_RIGHT_BALANCE); } else if (right < left) { vol = tosun(left/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN); bal = tosun(1.0 - right/left, AUDIO_MID_BALANCE, AUDIO_LEFT_BALANCE); } AUDIO_INITINFO(&info); info.play.gain = (long)(vol+0.5); info.play.balance = (long)(bal+0.5); if(ioctl(cfd, AUDIO_SETINFO, &info) < 0) oserror(); } static void getvolbal(int *left, int *right) { audio_info_t info; double gain, bal, vol, l, r; AUDIO_INITINFO(&info); if (ioctl(cfd, AUDIO_GETINFO, &info) < 0) oserror(); gain = info.play.gain; bal = info.play.balance; vol = fromsun(gain, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN) * 100.0; if (bal == AUDIO_MID_BALANCE) { l = r = vol; } else if (bal < AUDIO_MID_BALANCE) { l = vol; r = vol * (1.0 - fromsun(bal, AUDIO_MID_BALANCE, AUDIO_LEFT_BALANCE)); } else { r = vol; l = vol * (1.0 - fromsun(bal, AUDIO_MID_BALANCE, AUDIO_RIGHT_BALANCE)); } *left = (long)(l+0.5); *right = (long)(r+0.5); return; } void audiodevsetvol(int what, int left, int right) { audio_info_t info; ulong x; int l, r; if (afn == nil || cfn == nil) audiodevinit(); if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0) { cfd = -1; oserror(); } if(what == Vspeed){ x = left; AUDIO_INITINFO(&info); info.play.sample_rate = x; if(ioctl(cfd, AUDIO_SETINFO, &info) < 0) oserror(); speed = x; return; } if(what == Vaudio){ getvolbal(&l, &r); if (left < 0) setvolbal(l, right); else if (right < 0) setvolbal(left, r); else setvolbal(left, right); return; } } void audiodevgetvol(int what, int *left, int *right) { audio_info_t info; if (afn == nil || cfn == nil) audiodevinit(); if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0) { cfd = -1; oserror(); } switch(what) { case Vspeed: *left = *right = speed; break; case Vaudio: getvolbal(left, right); break; case Vtreb: case Vbass: *left = *right = 50; break; default: *left = *right = 0; } } static uchar *buf = 0; static int nbuf = 0; int audiodevwrite(void *v, int n) { int i, m, tot; uchar *p; if (needswap) { if (nbuf < n) { buf = (uchar*)erealloc(buf, n); if(buf == nil) panic("out of memory"); nbuf = n; } p = (uchar*)v; for(i=0; i+1 #ifdef __linux__ #include #else #include #endif #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "devaudio.h" enum { Channels = 2, Rate = 44100, Bits = 16, Bigendian = 1, }; static int afd = -1; static int cfd= -1; static int speed; /* maybe this should return -1 instead of sysfatal */ void audiodevopen(void) { int t; ulong ul; afd = -1; cfd = -1; if((afd = open("/dev/dsp", OWRITE)) < 0) goto err; if((cfd = open("/dev/mixer", ORDWR)) < 0) goto err; t = Bits; if(ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &t) < 0) goto err; t = Channels-1; if(ioctl(afd, SNDCTL_DSP_STEREO, &t) < 0) goto err; speed = Rate; ul = Rate; if(ioctl(afd, SNDCTL_DSP_SPEED, &ul) < 0) goto err; return; err: if(afd >= 0) close(afd); afd = -1; oserror(); } void audiodevclose(void) { close(afd); close(cfd); afd = -1; cfd = -1; } static struct { int id9; int id; } names[] = { Vaudio, SOUND_MIXER_VOLUME, Vbass, SOUND_MIXER_BASS, Vtreb, SOUND_MIXER_TREBLE, Vline, SOUND_MIXER_LINE, Vpcm, SOUND_MIXER_PCM, Vsynth, SOUND_MIXER_SYNTH, Vcd, SOUND_MIXER_CD, Vmic, SOUND_MIXER_MIC, // "record", SOUND_MIXER_RECLEV, // "mix", SOUND_MIXER_IMIX, // "pcm2", SOUND_MIXER_ALTPCM, Vspeaker, SOUND_MIXER_SPEAKER // "line1", SOUND_MIXER_LINE1, // "line2", SOUND_MIXER_LINE2, // "line3", SOUND_MIXER_LINE3, // "digital1", SOUND_MIXER_DIGITAL1, // "digital2", SOUND_MIXER_DIGITAL2, // "digital3", SOUND_MIXER_DIGITAL3, // "phonein", SOUND_MIXER_PHONEIN, // "phoneout", SOUND_MIXER_PHONEOUT, // "radio", SOUND_MIXER_RADIO, // "video", SOUND_MIXER_VIDEO, // "monitor", SOUND_MIXER_MONITOR, // "igain", SOUND_MIXER_IGAIN, // "ogain", SOUND_MIXER_OGAIN, }; static int lookname(int id9) { int i; for(i=0; i>8)&0xFF; } int audiodevwrite(void *v, int n) { int m, tot; for(tot=0; totlk) #define aqunlock(a) qunlock(&(a)->lk) static struct { char* name; int flag; int ilval; /* initial values */ int irval; } volumes[] = { "audio", Fout, 50, 50, "synth", Fin|Fout, 0, 0, "cd", Fin|Fout, 0, 0, "line", Fin|Fout, 0, 0, "mic", Fin|Fout|Fmono, 0, 0, "speaker", Fout|Fmono, 0, 0, "treb", Fout, 50, 50, "bass", Fout, 50, 50, "speed", Fin|Fout|Fmono, Speed, Speed, 0 }; static char Emode[] = "illegal open mode"; static char Evolume[] = "illegal volume specifier"; static void resetlevel(void) { int i; for(i=0; volumes[i].name; i++) audiodevsetvol(i, volumes[i].ilval, volumes[i].irval); } static void audioinit(void) { } static Chan* audioattach(char *param) { return devattach('A', param); } static Walkqid* audiowalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen); } static int audiostat(Chan *c, uchar *db, int n) { return devstat(c, db, n, audiodir, nelem(audiodir), devgen); } static Chan* audioopen(Chan *c, int omode) { int amode; switch((ulong)c->qid.path) { default: error(Eperm); break; case Qvolume: case Qdir: break; case Qaudio: amode = Awrite; if((omode&7) == OREAD) amode = Aread; aqlock(&audio); if(waserror()){ aqunlock(&audio); nexterror(); } if(audio.amode != Aclosed) error(Einuse); audiodevopen(); audio.amode = amode; poperror(); aqunlock(&audio); break; } c = devopen(c, omode, audiodir, nelem(audiodir), devgen); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } static void audioclose(Chan *c) { switch((ulong)c->qid.path) { default: error(Eperm); break; case Qdir: case Qvolume: break; case Qaudio: if(c->flag & COPEN) { aqlock(&audio); audiodevclose(); audio.amode = Aclosed; aqunlock(&audio); } break; } } static long audioread(Chan *c, void *v, long n, vlong off) { int liv, riv, lov, rov; long m; char buf[300]; int j; ulong offset = off; char *a; a = v; switch((ulong)c->qid.path) { default: error(Eperm); break; case Qdir: return devdirread(c, a, n, audiodir, nelem(audiodir), devgen); case Qaudio: if(audio.amode != Aread) error(Emode); aqlock(&audio); if(waserror()){ aqunlock(&audio); nexterror(); } n = audiodevread(v, n); poperror(); aqunlock(&audio); break; case Qvolume: j = 0; buf[0] = 0; for(m=0; volumes[m].name; m++){ audiodevgetvol(m, &lov, &rov); liv = lov; riv = rov; j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name); if((volumes[m].flag & Fmono) || (liv==riv && lov==rov)){ if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov) j += snprint(buf+j, sizeof(buf)-j, " %d", liv); else{ if(volumes[m].flag & Fin) j += snprint(buf+j, sizeof(buf)-j, " in %d", liv); if(volumes[m].flag & Fout) j += snprint(buf+j, sizeof(buf)-j, " out %d", lov); } }else{ if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov && riv==rov) j += snprint(buf+j, sizeof(buf)-j, " left %d right %d", liv, riv); else{ if(volumes[m].flag & Fin) j += snprint(buf+j, sizeof(buf)-j, " in left %d right %d", liv, riv); if(volumes[m].flag & Fout) j += snprint(buf+j, sizeof(buf)-j, " out left %d right %d", lov, rov); } } j += snprint(buf+j, sizeof(buf)-j, "\n"); } return readstr(offset, a, n, buf); } return n; } static long audiowrite(Chan *c, void *vp, long n, vlong off) { long m; int i, v, left, right, out; Cmdbuf *cb; USED(off); switch((ulong)c->qid.path) { default: error(Eperm); break; case Qvolume: v = Vaudio; left = 1; right = 1; out = 1; cb = parsecmd(vp, n); if(waserror()){ free(cb); nexterror(); } for(i = 0; i < cb->nf; i++){ /* * a number is volume */ if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') { m = strtoul(cb->f[i], 0, 10); if(!out) goto cont0; if(left && right) audiodevsetvol(v, m, m); else if(left) audiodevsetvol(v, m, -1); else if(right) audiodevsetvol(v, -1, m); goto cont0; } for(m=0; volumes[m].name; m++) { if(strcmp(cb->f[i], volumes[m].name) == 0) { v = m; out = 1; left = 1; right = 1; goto cont0; } } if(strcmp(cb->f[i], "reset") == 0) { resetlevel(); goto cont0; } if(strcmp(cb->f[i], "in") == 0) { out = 0; goto cont0; } if(strcmp(cb->f[i], "out") == 0) { out = 1; goto cont0; } if(strcmp(cb->f[i], "left") == 0) { left = 1; right = 0; goto cont0; } if(strcmp(cb->f[i], "right") == 0) { left = 0; right = 1; goto cont0; } error(Evolume); break; cont0:; } free(cb); poperror(); break; case Qaudio: if(audio.amode != Awrite) error(Emode); aqlock(&audio); if(waserror()){ aqunlock(&audio); nexterror(); } n = audiodevwrite(vp, n); poperror(); aqunlock(&audio); break; } return n; } void audioswab(uchar *a, uint n) { ulong *p, *ep, b; p = (ulong*)a; ep = p + (n>>2); while(p < ep) { b = *p; b = (b>>24) | (b<<24) | ((b&0xff0000) >> 8) | ((b&0x00ff00) << 8); *p++ = b; } } Dev audiodevtab = { 'A', "audio", devreset, audioinit, devshutdown, audioattach, audiowalk, audiostat, audioopen, devcreate, audioclose, audioread, devbread, audiowrite, devbwrite, devremove, devwstat, }; drawterm-20170818/kern/devaudio.h000066400000000000000000000005101314554504700165270ustar00rootroot00000000000000enum { Fmono = 1, Fin = 2, Fout = 4, Vaudio = 0, Vsynth, Vcd, Vline, Vmic, Vspeaker, Vtreb, Vbass, Vspeed, Vpcm, Nvol, }; void audiodevopen(void); void audiodevclose(void); int audiodevread(void*, int); int audiodevwrite(void*, int); void audiodevgetvol(int, int*, int*); void audiodevsetvol(int, int, int); drawterm-20170818/kern/devcons.c000066400000000000000000000463651314554504700164050ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "keyboard.h" void (*consdebug)(void) = 0; void (*screenputs)(char*, int) = 0; Queue* kbdq; /* unprocessed console input */ Queue* lineq; /* processed console input */ Queue* serialoq; /* serial console output */ Queue* kprintoq; /* console output, for /dev/kprint */ long kprintinuse; /* test and set whether /dev/kprint is open */ Lock kprintlock; int iprintscreenputs = 0; int panicking; struct { int exiting; int machs; } active; static struct { QLock lk; int raw; /* true if we shouldn't process input */ int ctl; /* number of opens to the control file */ int x; /* index into line */ char line[1024]; /* current input line */ int count; int ctlpoff; /* a place to save up characters at interrupt time before dumping them in the queue */ Lock lockputc; char istage[1024]; char *iw; char *ir; char *ie; } kbd = { { 0 }, 0, 0, 0, { 0 }, 0, 0, { 0 }, { 0 }, kbd.istage, kbd.istage, kbd.istage + sizeof(kbd.istage), }; char *sysname; vlong fasthz; static int readtime(ulong, char*, int); static int readbintime(char*, int); static int writetime(char*, int); static int writebintime(char*, int); enum { CMreboot, CMpanic, }; Cmdtab rebootmsg[] = { CMreboot, "reboot", 0, CMpanic, "panic", 0, }; int return0(void *v) { return 0; } void printinit(void) { lineq = qopen(2*1024, 0, 0, nil); if(lineq == nil) panic("printinit"); qnoblock(lineq, 1); kbdq = qopen(4*1024, 0, 0, 0); if(kbdq == nil) panic("kbdinit"); qnoblock(kbdq, 1); } int consactive(void) { if(serialoq) return qlen(serialoq) > 0; return 0; } void prflush(void) { /* ulong now; now = m->ticks; while(consactive()) if(m->ticks - now >= HZ) break; */ } /* * Print a string on the console. Convert \n to \r\n for serial * line consoles. Locking of the queues is left up to the screen * or uart code. Multi-line messages to serial consoles may get * interspersed with other messages. */ static void putstrn0(char *str, int n, int usewrite) { /* * if someone is reading /dev/kprint, * put the message there. * if not and there's an attached bit mapped display, * put the message there. * * if there's a serial line being used as a console, * put the message there. */ if(kprintoq != nil && !qisclosed(kprintoq)){ if(usewrite) qwrite(kprintoq, str, n); else qiwrite(kprintoq, str, n); }else if(screenputs != 0) screenputs(str, n); } void putstrn(char *str, int n) { putstrn0(str, n, 0); } int noprint; int print(char *fmt, ...) { int n; va_list arg; char buf[PRINTSIZE]; if(noprint) return -1; va_start(arg, fmt); n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); putstrn(buf, n); return n; } void panic(char *fmt, ...) { int n; va_list arg; char buf[PRINTSIZE]; kprintoq = nil; /* don't try to write to /dev/kprint */ if(panicking) for(;;); panicking = 1; splhi(); strcpy(buf, "panic: "); va_start(arg, fmt); n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf; va_end(arg); buf[n] = '\n'; uartputs(buf, n+1); if(consdebug) (*consdebug)(); spllo(); prflush(); putstrn(buf, n+1); dumpstack(); exit(1); } int pprint(char *fmt, ...) { int n; Chan *c; va_list arg; char buf[2*PRINTSIZE]; if(up == nil || up->fgrp == nil) return 0; c = up->fgrp->fd[2]; if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) return 0; n = sprint(buf, "%s %lud: ", up->text, up->pid); va_start(arg, fmt); n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); if(waserror()) return 0; devtab[c->type]->write(c, buf, n, c->offset); poperror(); lock(&c->ref.lk); c->offset += n; unlock(&c->ref.lk); return n; } static void echoscreen(char *buf, int n) { char *e, *p; char ebuf[128]; int x; p = ebuf; e = ebuf + sizeof(ebuf) - 4; while(n-- > 0){ if(p >= e){ screenputs(ebuf, p - ebuf); p = ebuf; } x = *buf++; if(x == 0x15){ *p++ = '^'; *p++ = 'U'; *p++ = '\n'; } else *p++ = x; } if(p != ebuf) screenputs(ebuf, p - ebuf); } static void echoserialoq(char *buf, int n) { char *e, *p; char ebuf[128]; int x; p = ebuf; e = ebuf + sizeof(ebuf) - 4; while(n-- > 0){ if(p >= e){ qiwrite(serialoq, ebuf, p - ebuf); p = ebuf; } x = *buf++; if(x == '\n'){ *p++ = '\r'; *p++ = '\n'; } else if(x == 0x15){ *p++ = '^'; *p++ = 'U'; *p++ = '\n'; } else *p++ = x; } if(p != ebuf) qiwrite(serialoq, ebuf, p - ebuf); } static void echo(char *buf, int n) { static int ctrlt; int x; char *e, *p; e = buf+n; for(p = buf; p < e; p++){ switch(*p){ case 0x10: /* ^P */ if(cpuserver && !kbd.ctlpoff){ active.exiting = 1; return; } break; case 0x14: /* ^T */ ctrlt++; if(ctrlt > 2) ctrlt = 2; continue; } if(ctrlt != 2) continue; /* ^T escapes */ ctrlt = 0; switch(*p){ case 'S': x = splhi(); dumpstack(); procdump(); splx(x); return; case 's': dumpstack(); return; case 'x': xsummary(); ixsummary(); mallocsummary(); pagersummary(); return; case 'd': if(consdebug == 0) consdebug = rdb; else consdebug = 0; print("consdebug now 0x%p\n", consdebug); return; case 'D': if(consdebug == 0) consdebug = rdb; consdebug(); return; case 'p': x = spllo(); procdump(); splx(x); return; case 'q': scheddump(); return; case 'k': killbig(); return; case 'r': exit(0); return; } } qproduce(kbdq, buf, n); if(kbd.raw) return; if(screenputs != 0) echoscreen(buf, n); if(serialoq) echoserialoq(buf, n); } /* * Called by a uart interrupt for console input. * * turn '\r' into '\n' before putting it into the queue. */ int kbdcr2nl(Queue *q, int ch) { char *next; USED(q); ilock(&kbd.lockputc); /* just a mutex */ if(ch == '\r' && !kbd.raw) ch = '\n'; next = kbd.iw+1; if(next >= kbd.ie) next = kbd.istage; if(next != kbd.ir){ *kbd.iw = ch; kbd.iw = next; } iunlock(&kbd.lockputc); return 0; } static void _kbdputc(int c) { Rune r; char buf[UTFmax]; int n; r = c; n = runetochar(buf, &r); if(n == 0) return; echo(buf, n); // kbd.c = r; // qproduce(kbdq, buf, n); } /* _kbdputc, but with compose translation */ int kbdputc(Queue *q, int c) { int i; static int collecting, nk; static Rune kc[5]; if(c == Kalt){ collecting = 1; nk = 0; return 0; } if(!collecting){ _kbdputc(c); return 0; } kc[nk++] = c; c = latin1(kc, nk); if(c < -1) /* need more keystrokes */ return 0; if(c != -1) /* valid sequence */ _kbdputc(c); else for(i=0; i= size) return 0; if(off+n > size) n = size-off; memmove(buf, tmp+off, n); return n; } int readstr(ulong off, char *buf, ulong n, char *str) { int size; size = strlen(str); if(off >= size) return 0; if(off+n > size) n = size-off; memmove(buf, str+off, n); return n; } static void consinit(void) { todinit(); randominit(); /* * at 115200 baud, the 1024 char buffer takes 56 ms to process, * processing it every 22 ms should be fine */ /* addclock0link(kbdputcclock, 22); */ } static Chan* consattach(char *spec) { return devattach('c', spec); } static Walkqid* conswalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen); } static int consstat(Chan *c, uchar *dp, int n) { return devstat(c, dp, n, consdir, nelem(consdir), devgen); } static Chan* consopen(Chan *c, int omode) { c->aux = nil; c = devopen(c, omode, consdir, nelem(consdir), devgen); switch((ulong)c->qid.path){ case Qconsctl: qlock(&kbd.lk); kbd.ctl++; qunlock(&kbd.lk); break; case Qkprint: lock(&kprintlock); if(kprintinuse != 0){ c->flag &= ~COPEN; unlock(&kprintlock); error(Einuse); } kprintinuse = 1; unlock(&kprintlock); if(kprintoq == nil){ kprintoq = qopen(8*1024, Qcoalesce, 0, 0); if(kprintoq == nil){ c->flag &= ~COPEN; error(Enomem); } qnoblock(kprintoq, 1); }else qreopen(kprintoq); c->iounit = qiomaxatomic; break; case Qsecstore: if(omode == ORDWR) error(Eperm); if(omode != OREAD) memset(secstorebuf, 0, sizeof secstorebuf); break; case Qsnarf: if(omode == ORDWR) error(Eperm); if(omode == OREAD) c->aux = strdup(""); else c->aux = mallocz(SnarfSize, 1); break; } return c; } static void consclose(Chan *c) { switch((ulong)c->qid.path){ /* last close of control file turns off raw */ case Qconsctl: if(c->flag&COPEN){ qlock(&kbd.lk); if(--kbd.ctl == 0) kbd.raw = 0; qunlock(&kbd.lk); } break; /* close of kprint allows other opens */ case Qkprint: if(c->flag & COPEN){ kprintinuse = 0; qhangup(kprintoq, nil); } break; case Qsnarf: if(c->mode == OWRITE) clipwrite(c->aux); free(c->aux); break; } } static long consread(Chan *c, void *buf, long n, vlong off) { char *b; char tmp[128]; /* must be >= 6*NUMSIZE */ char *cbuf = buf; int ch, i, eol; vlong offset = off; if(n <= 0) return n; switch((ulong)c->qid.path){ case Qdir: return devdirread(c, buf, n, consdir, nelem(consdir), devgen); case Qcons: qlock(&kbd.lk); if(waserror()) { qunlock(&kbd.lk); nexterror(); } if(kbd.raw) { if(qcanread(lineq)) n = qread(lineq, buf, n); else { /* read as much as possible */ do { i = qread(kbdq, cbuf, n); cbuf += i; n -= i; } while (n>0 && qcanread(kbdq)); n = cbuf - (char*)buf; } } else { while(!qcanread(lineq)) { qread(kbdq, &kbd.line[kbd.x], 1); ch = kbd.line[kbd.x]; eol = 0; switch(ch){ case '\b': if(kbd.x) kbd.x--; break; case 0x15: kbd.x = 0; break; case '\n': case 0x04: eol = 1; default: kbd.line[kbd.x++] = ch; break; } if(kbd.x == sizeof(kbd.line) || eol){ if(ch == 0x04) kbd.x--; qwrite(lineq, kbd.line, kbd.x); kbd.x = 0; } } n = qread(lineq, buf, n); } qunlock(&kbd.lk); poperror(); return n; case Qcpunote: sleep(&up->sleep, return0, nil); case Qcputime: return 0; case Qkprint: return qread(kprintoq, buf, n); case Qpgrpid: return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE); case Qpid: return readnum((ulong)offset, buf, n, up->pid, NUMSIZE); case Qppid: return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE); case Qtime: return readtime((ulong)offset, buf, n); case Qbintime: return readbintime(buf, n); case Qhostowner: return readstr((ulong)offset, buf, n, eve); case Qhostdomain: return readstr((ulong)offset, buf, n, hostdomain); case Quser: return readstr((ulong)offset, buf, n, up->user); case Qnull: return 0; case Qsnarf: if(offset == 0){ free(c->aux); c->aux = clipread(); } if(c->aux == nil) return 0; return readstr(offset, buf, n, c->aux); case Qsecstore: return readstr(offset, buf, n, secstorebuf); case Qsysstat: return 0; case Qswap: return 0; case Qsysname: if(sysname == nil) return 0; return readstr((ulong)offset, buf, n, sysname); case Qrandom: return randomread(buf, n); case Qdrivers: b = malloc(READSTR); if(b == nil) error(Enomem); n = 0; for(i = 0; devtab[i] != nil; i++) n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc, devtab[i]->name); if(waserror()){ free(b); nexterror(); } n = readstr((ulong)offset, buf, n, b); free(b); poperror(); return n; case Qzero: memset(buf, 0, n); return n; case Qosversion: snprint(tmp, sizeof tmp, "2000"); n = readstr((ulong)offset, buf, n, tmp); return n; default: print("consread 0x%llux\n", c->qid.path); error(Egreg); } return -1; /* never reached */ } static long conswrite(Chan *c, void *va, long n, vlong off) { char buf[256]; long l, bp; char *a = va; int fd; Chan *swc; ulong offset = off; Cmdbuf *cb; Cmdtab *ct; switch((ulong)c->qid.path){ case Qcons: /* * Can't page fault in putstrn, so copy the data locally. */ l = n; while(l > 0){ bp = l; if(bp > sizeof buf) bp = sizeof buf; memmove(buf, a, bp); putstrn0(buf, bp, 1); a += bp; l -= bp; } break; case Qconsctl: if(n >= sizeof(buf)) n = sizeof(buf)-1; strncpy(buf, a, n); buf[n] = 0; for(a = buf; a;){ if(strncmp(a, "rawon", 5) == 0){ qlock(&kbd.lk); if(kbd.x){ qwrite(kbdq, kbd.line, kbd.x); kbd.x = 0; } kbd.raw = 1; qunlock(&kbd.lk); } else if(strncmp(a, "rawoff", 6) == 0){ qlock(&kbd.lk); kbd.raw = 0; kbd.x = 0; qunlock(&kbd.lk); } else if(strncmp(a, "ctlpon", 6) == 0){ kbd.ctlpoff = 0; } else if(strncmp(a, "ctlpoff", 7) == 0){ kbd.ctlpoff = 1; } if((a = strchr(a, ' '))) a++; } break; case Qtime: if(!iseve()) error(Eperm); return writetime(a, n); case Qbintime: if(!iseve()) error(Eperm); return writebintime(a, n); case Qhostowner: return hostownerwrite(a, n); case Qhostdomain: return hostdomainwrite(a, n); case Quser: return userwrite(a, n); case Qnull: break; case Qreboot: if(!iseve()) error(Eperm); cb = parsecmd(a, n); if(waserror()) { free(cb); nexterror(); } ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg)); switch(ct->index) { case CMreboot: rebootcmd(cb->nf-1, cb->f+1); break; case CMpanic: panic("/dev/reboot"); } poperror(); free(cb); break; case Qsecstore: if(offset >= sizeof secstorebuf || offset+n+1 >= sizeof secstorebuf) error(Etoobig); secstoretab->qid.vers++; memmove(secstorebuf+offset, va, n); return n; case Qshowfile: return showfilewrite(a, n); case Qsnarf: if(offset >= SnarfSize || offset+n >= SnarfSize) error(Etoobig); snarftab->qid.vers++; memmove((uchar*)c->aux+offset, va, n); return n; case Qsysstat: n = 0; break; case Qswap: if(n >= sizeof buf) error(Egreg); memmove(buf, va, n); /* so we can NUL-terminate */ buf[n] = 0; /* start a pager if not already started */ if(strncmp(buf, "start", 5) == 0){ kickpager(); break; } if(cpuserver && !iseve()) error(Eperm); if(buf[0]<'0' || '9'= sizeof buf) error(Ebadarg); strncpy(buf, a, n); buf[n] = 0; if(buf[n-1] == '\n') buf[n-1] = 0; kstrdup(&sysname, buf); break; default: print("conswrite: 0x%llux\n", c->qid.path); error(Egreg); } return n; } Dev consdevtab = { 'c', "cons", devreset, consinit, devshutdown, consattach, conswalk, consstat, consopen, devcreate, consclose, consread, devbread, conswrite, devbwrite, devremove, devwstat, }; static uvlong uvorder = (uvlong) 0x0001020304050607ULL; static uchar* le2vlong(vlong *to, uchar *f) { uchar *t, *o; int i; t = (uchar*)to; o = (uchar*)&uvorder; for(i = 0; i < sizeof(vlong); i++) t[o[i]] = f[i]; return f+sizeof(vlong); } static uchar* vlong2le(uchar *t, vlong from) { uchar *f, *o; int i; f = (uchar*)&from; o = (uchar*)&uvorder; for(i = 0; i < sizeof(vlong); i++) t[i] = f[o[i]]; return t+sizeof(vlong); } static long order = 0x00010203; static uchar* le2long(long *to, uchar *f) { uchar *t, *o; int i; t = (uchar*)to; o = (uchar*)ℴ for(i = 0; i < sizeof(long); i++) t[o[i]] = f[i]; return f+sizeof(long); } /* static uchar* long2le(uchar *t, long from) { uchar *f, *o; int i; f = (uchar*)&from; o = (uchar*)ℴ for(i = 0; i < sizeof(long); i++) t[i] = f[o[i]]; return t+sizeof(long); } */ char *Ebadtimectl = "bad time control"; /* * like the old #c/time but with added info. Return * * secs nanosecs fastticks fasthz */ static int readtime(ulong off, char *buf, int n) { vlong nsec, ticks; long sec; char str[7*NUMSIZE]; nsec = todget(&ticks); if(fasthz == (vlong)0) fastticks((uvlong*)&fasthz); sec = nsec/((uvlong) 1000000000); snprint(str, sizeof(str), "%*.0lud %*.0llud %*.0llud %*.0llud ", NUMSIZE-1, sec, VLNUMSIZE-1, nsec, VLNUMSIZE-1, ticks, VLNUMSIZE-1, fasthz); return readstr(off, buf, n, str); } /* * set the time in seconds */ static int writetime(char *buf, int n) { char b[13]; long i; vlong now; if(n >= sizeof(b)) error(Ebadtimectl); strncpy(b, buf, n); b[n] = 0; i = strtol(b, 0, 0); if(i <= 0) error(Ebadtimectl); now = i*((vlong) 1000000000); todset(now, 0, 0); return n; } /* * read binary time info. all numbers are little endian. * ticks and nsec are syncronized. */ static int readbintime(char *buf, int n) { int i; vlong nsec, ticks; uchar *b = (uchar*)buf; i = 0; if(fasthz == (vlong)0) fastticks((uvlong*)&fasthz); nsec = todget(&ticks); if(n >= 3*sizeof(uvlong)){ vlong2le(b+2*sizeof(uvlong), fasthz); i += sizeof(uvlong); } if(n >= 2*sizeof(uvlong)){ vlong2le(b+sizeof(uvlong), ticks); i += sizeof(uvlong); } if(n >= 8){ vlong2le(b, nsec); i += sizeof(vlong); } return i; } /* * set any of the following * - time in nsec * - nsec trim applied over some seconds * - clock frequency */ static int writebintime(char *buf, int n) { uchar *p; vlong delta; long period; n--; p = (uchar*)buf + 1; switch(*buf){ case 'n': if(n < sizeof(vlong)) error(Ebadtimectl); le2vlong(&delta, p); todset(delta, 0, 0); break; case 'd': if(n < sizeof(vlong)+sizeof(long)) error(Ebadtimectl); p = le2vlong(&delta, p); le2long(&period, p); todset(-1, delta, period); break; case 'f': if(n < sizeof(uvlong)) error(Ebadtimectl); le2vlong(&fasthz, p); todsetfreq(fasthz); break; } return n; } int iprint(char *fmt, ...) { int n, s; va_list arg; char buf[PRINTSIZE]; s = splhi(); va_start(arg, fmt); n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); if(screenputs != 0 && iprintscreenputs) screenputs(buf, n); #undef write write(2, buf, n); splx(s); return n; } drawterm-20170818/kern/devdraw.c000066400000000000000000001246431314554504700163740ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #define Image IMAGE #include #include #include #include #include "screen.h" enum { Qtopdir = 0, Qnew, Q3rd, Q2nd, Qcolormap, Qctl, Qdata, Qrefresh, }; /* * Qid path is: * 4 bits of file type (qids above) * 24 bits of mux slot number +1; 0 means not attached to client */ #define QSHIFT 4 /* location in qid of client # */ #define QID(q) ((((ulong)(q).path)&0x0000000F)>>0) #define CLIENTPATH(q) ((((ulong)q)&0x7FFFFFF0)>>QSHIFT) #define CLIENT(q) CLIENTPATH((q).path) #define NHASH (1<<5) #define HASHMASK (NHASH-1) #define IOUNIT (64*1024) typedef struct Client Client; typedef struct Draw Draw; typedef struct DImage DImage; typedef struct DScreen DScreen; typedef struct CScreen CScreen; typedef struct FChar FChar; typedef struct Refresh Refresh; typedef struct Refx Refx; typedef struct DName DName; ulong blanktime = 30; /* in minutes; a half hour */ struct Draw { QLock lk; int clientid; int nclient; Client** client; int nname; DName* name; int vers; int softscreen; int blanked; /* screen turned off */ ulong blanktime; /* time of last operation */ ulong savemap[3*256]; }; struct Client { Ref r; DImage* dimage[NHASH]; CScreen* cscreen; Refresh* refresh; Rendez refrend; uchar* readdata; int nreaddata; int busy; int clientid; int slot; int refreshme; int infoid; int op; }; struct Refresh { DImage* dimage; Rectangle r; Refresh* next; }; struct Refx { Client* client; DImage* dimage; }; struct DName { char *name; Client *client; DImage* dimage; int vers; }; struct FChar { int minx; /* left edge of bits */ int maxx; /* right edge of bits */ uchar miny; /* first non-zero scan-line */ uchar maxy; /* last non-zero scan-line + 1 */ schar left; /* offset of baseline */ uchar width; /* width of baseline */ }; /* * Reference counts in DImages: * one per open by original client * one per screen image or fill * one per image derived from this one by name */ struct DImage { int id; int ref; char *name; int vers; Memimage* image; int ascent; int nfchar; FChar* fchar; DScreen* dscreen; /* 0 if not a window */ DImage* fromname; /* image this one is derived from, by name */ DImage* next; }; struct CScreen { DScreen* dscreen; CScreen* next; }; struct DScreen { int id; int public; int ref; DImage *dimage; DImage *dfill; Memscreen* screen; Client* owner; DScreen* next; }; static Draw sdraw; static Memimage *screenimage; static Memdata screendata; static Rectangle flushrect; static int waste; static DScreen* dscreen; extern void flushmemscreen(Rectangle); void drawmesg(Client*, void*, int); void drawuninstall(Client*, int); void drawfreedimage(DImage*); Client* drawclientofpath(ulong); static char Enodrawimage[] = "unknown id for draw image"; static char Enodrawscreen[] = "unknown id for draw screen"; static char Eshortdraw[] = "short draw message"; static char Eshortread[] = "draw read too short"; static char Eimageexists[] = "image id in use"; static char Escreenexists[] = "screen id in use"; static char Edrawmem[] = "image memory allocation failed"; static char Ereadoutside[] = "readimage outside image"; static char Ewriteoutside[] = "writeimage outside image"; static char Enotfont[] = "image not a font"; static char Eindex[] = "character index out of range"; static char Enoclient[] = "no such draw client"; /* static char Edepth[] = "image has bad depth"; */ static char Enameused[] = "image name in use"; static char Enoname[] = "no image with that name"; static char Eoldname[] = "named image no longer valid"; static char Enamed[] = "image already has name"; static char Ewrongname[] = "wrong name for image"; int drawcanqlock(void) { return canqlock(&sdraw.lk); } void drawqlock(void) { qlock(&sdraw.lk); } void drawqunlock(void) { qunlock(&sdraw.lk); } static int drawgen(Chan *c, char *name, Dirtab *dt, int ndt, int s, Dir *dp) { int t; Qid q; ulong path; Client *cl; USED(name); USED(dt); USED(ndt); q.vers = 0; if(s == DEVDOTDOT){ switch(QID(c->qid)){ case Qtopdir: case Q2nd: mkqid(&q, Qtopdir, 0, QTDIR); devdir(c, q, "#i", 0, eve, 0500, dp); break; case Q3rd: cl = drawclientofpath(c->qid.path); if(cl == nil) strcpy(up->genbuf, "??"); else sprint(up->genbuf, "%d", cl->clientid); mkqid(&q, Q2nd, 0, QTDIR); devdir(c, q, up->genbuf, 0, eve, 0500, dp); break; default: panic("drawwalk %llux", c->qid.path); } return 1; } /* * Top level directory contains the name of the device. */ t = QID(c->qid); if(t == Qtopdir){ switch(s){ case 0: mkqid(&q, Q2nd, 0, QTDIR); devdir(c, q, "draw", 0, eve, 0555, dp); break; default: return -1; } return 1; } /* * Second level contains "new" plus all the clients. */ if(t == Q2nd || t == Qnew){ if(s == 0){ mkqid(&q, Qnew, 0, QTFILE); devdir(c, q, "new", 0, eve, 0666, dp); } else if(s <= sdraw.nclient){ cl = sdraw.client[s-1]; if(cl == 0) return 0; sprint(up->genbuf, "%d", cl->clientid); mkqid(&q, (s<genbuf, 0, eve, 0555, dp); return 1; } else return -1; return 1; } /* * Third level. */ path = c->qid.path&~((1<qid.vers; q.type = QTFILE; switch(s){ case 0: q.path = path|Qcolormap; devdir(c, q, "colormap", 0, eve, 0600, dp); break; case 1: q.path = path|Qctl; devdir(c, q, "ctl", 0, eve, 0600, dp); break; case 2: q.path = path|Qdata; devdir(c, q, "data", 0, eve, 0600, dp); break; case 3: q.path = path|Qrefresh; devdir(c, q, "refresh", 0, eve, 0400, dp); break; default: return -1; } return 1; } static int drawrefactive(void *a) { Client *c; c = a; return c->refreshme || c->refresh!=0; } static void drawrefreshscreen(DImage *l, Client *client) { while(l != nil && l->dscreen == nil) l = l->fromname; if(l != nil && l->dscreen->owner != client) l->dscreen->owner->refreshme = 1; } static void drawrefresh(Memimage *m, Rectangle r, void *v) { Refx *x; DImage *d; Client *c; Refresh *ref; USED(m); if(v == 0) return; x = v; c = x->client; d = x->dimage; for(ref=c->refresh; ref; ref=ref->next) if(ref->dimage == d){ combinerect(&ref->r, r); return; } ref = malloc(sizeof(Refresh)); if(ref){ ref->dimage = d; ref->r = r; ref->next = c->refresh; c->refresh = ref; } } static void addflush(Rectangle r) { int abb, ar, anbb; Rectangle nbb; if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r)) return; if(flushrect.min.x >= flushrect.max.x){ flushrect = r; waste = 0; return; } nbb = flushrect; combinerect(&nbb, r); ar = Dx(r)*Dy(r); abb = Dx(flushrect)*Dy(flushrect); anbb = Dx(nbb)*Dy(nbb); /* * Area of new waste is area of new bb minus area of old bb, * less the area of the new segment, which we assume is not waste. * This could be negative, but that's OK. */ waste += anbb-abb - ar; if(waste < 0) waste = 0; /* * absorb if: * total area is small * waste is less than half total area * rectangles touch */ if(anbb<=1024 || waste*2layer; if(l == nil) return; do{ if(l->screen->image->data != screenimage->data) return; r = rectaddpt(r, l->delta); l = l->screen->image->layer; }while(l); addflush(r); } void drawflush(void) { if(flushrect.min.x < flushrect.max.x) flushmemscreen(flushrect); flushrect = Rect(10000, 10000, -10000, -10000); } void drawflushr(Rectangle r) { qlock(&sdraw.lk); flushmemscreen(r); qunlock(&sdraw.lk); } static int drawcmp(char *a, char *b, int n) { if(strlen(a) != n) return 1; return memcmp(a, b, n); } DName* drawlookupname(int n, char *str) { DName *name, *ename; name = sdraw.name; ename = &name[sdraw.nname]; for(; namename, str, n) == 0) return name; return 0; } int drawgoodname(DImage *d) { DName *n; /* if window, validate the screen's own images */ if(d->dscreen) if(drawgoodname(d->dscreen->dimage) == 0 || drawgoodname(d->dscreen->dfill) == 0) return 0; if(d->name == nil) return 1; n = drawlookupname(strlen(d->name), d->name); if(n==nil || n->vers!=d->vers) return 0; return 1; } DImage* drawlookup(Client *client, int id, int checkname) { DImage *d; d = client->dimage[id&HASHMASK]; while(d){ if(d->id == id){ if(checkname && !drawgoodname(d)) error(Eoldname); return d; } d = d->next; } return 0; } DScreen* drawlookupdscreen(int id) { DScreen *s; s = dscreen; while(s){ if(s->id == id) return s; s = s->next; } return 0; } DScreen* drawlookupscreen(Client *client, int id, CScreen **cs) { CScreen *s; s = client->cscreen; while(s){ if(s->dscreen->id == id){ *cs = s; return s->dscreen; } s = s->next; } error(Enodrawscreen); return 0; } Memimage* drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen) { DImage *d; d = malloc(sizeof(DImage)); if(d == 0) return 0; d->id = id; d->ref = 1; d->name = 0; d->vers = 0; d->image = i; d->nfchar = 0; d->fchar = 0; d->fromname = 0; d->dscreen = dscreen; d->next = client->dimage[id&HASHMASK]; client->dimage[id&HASHMASK] = d; return i; } Memscreen* drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public) { Memscreen *s; CScreen *c; c = malloc(sizeof(CScreen)); if(dimage && dimage->image && dimage->image->chan == 0) panic("bad image %p in drawinstallscreen", dimage->image); if(c == 0) return 0; if(d == 0){ d = malloc(sizeof(DScreen)); if(d == 0){ free(c); return 0; } s = malloc(sizeof(Memscreen)); if(s == 0){ free(c); free(d); return 0; } s->frontmost = 0; s->rearmost = 0; d->dimage = dimage; if(dimage){ s->image = dimage->image; dimage->ref++; } d->dfill = dfill; if(dfill){ s->fill = dfill->image; dfill->ref++; } d->ref = 0; d->id = id; d->screen = s; d->public = public; d->next = dscreen; d->owner = client; dscreen = d; } c->dscreen = d; d->ref++; c->next = client->cscreen; client->cscreen = c; return d->screen; } void drawdelname(DName *name) { int i; i = name-sdraw.name; memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName)); sdraw.nname--; } void drawfreedscreen(DScreen *this) { DScreen *ds, *next; this->ref--; if(this->ref < 0) print("negative ref in drawfreedscreen\n"); if(this->ref > 0) return; ds = dscreen; if(ds == this){ dscreen = this->next; goto Found; } while((next = ds->next)){ /* assign = */ if(next == this){ ds->next = this->next; goto Found; } ds = next; } error(Enodrawimage); Found: if(this->dimage) drawfreedimage(this->dimage); if(this->dfill) drawfreedimage(this->dfill); free(this->screen); free(this); } void drawfreedimage(DImage *dimage) { int i; Memimage *l; DScreen *ds; dimage->ref--; if(dimage->ref < 0) print("negative ref in drawfreedimage\n"); if(dimage->ref > 0) return; /* any names? */ for(i=0; ifromname){ /* acquired by name; owned by someone else*/ drawfreedimage(dimage->fromname); goto Return; } if(dimage->image == screenimage) /* don't free the display */ goto Return; ds = dimage->dscreen; if(ds){ l = dimage->image; if(l->data == screenimage->data) addflush(l->layer->screenr); if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */ free(l->layer->refreshptr); l->layer->refreshptr = nil; if(drawgoodname(dimage)) memldelete(l); else memlfree(l); drawfreedscreen(ds); }else freememimage(dimage->image); Return: free(dimage->fchar); free(dimage); } void drawuninstallscreen(Client *client, CScreen *this) { CScreen *cs, *next; cs = client->cscreen; if(cs == this){ client->cscreen = this->next; drawfreedscreen(this->dscreen); free(this); return; } while((next = cs->next)){ /* assign = */ if(next == this){ cs->next = this->next; drawfreedscreen(this->dscreen); free(this); return; } cs = next; } } void drawuninstall(Client *client, int id) { DImage *d, *next; d = client->dimage[id&HASHMASK]; if(d == 0) error(Enodrawimage); if(d->id == id){ client->dimage[id&HASHMASK] = d->next; drawfreedimage(d); return; } while((next = d->next)){ /* assign = */ if(next->id == id){ d->next = next->next; drawfreedimage(next); return; } d = next; } error(Enodrawimage); } void drawaddname(Client *client, DImage *di, int n, char *str) { DName *name, *ename, *new, *t; name = sdraw.name; ename = &name[sdraw.nname]; for(; namename, str, n) == 0) error(Enameused); t = smalloc((sdraw.nname+1)*sizeof(DName)); memmove(t, sdraw.name, sdraw.nname*sizeof(DName)); free(sdraw.name); sdraw.name = t; new = &sdraw.name[sdraw.nname++]; new->name = smalloc(n+1); memmove(new->name, str, n); new->name[n] = 0; new->dimage = di; new->client = client; new->vers = ++sdraw.vers; } Client* drawnewclient(void) { Client *cl, **cp; int i; for(i=0; islot = i; cl->clientid = ++sdraw.clientid; cl->op = SoverD; sdraw.client[i] = cl; return cl; } static int drawclientop(Client *cl) { int op; op = cl->op; cl->op = SoverD; return op; } int drawhasclients(void) { /* * if draw has ever been used, we can't resize the frame buffer, * even if all clients have exited (nclients is cumulative); it's too * hard to make work. */ return sdraw.nclient != 0; } Client* drawclientofpath(ulong path) { Client *cl; int slot; slot = CLIENTPATH(path); if(slot == 0) return nil; cl = sdraw.client[slot-1]; if(cl==0 || cl->clientid==0) return nil; return cl; } Client* drawclient(Chan *c) { Client *client; client = drawclientofpath(c->qid.path); if(client == nil) error(Enoclient); return client; } Memimage* drawimage(Client *client, uchar *a) { DImage *d; d = drawlookup(client, BGLONG(a), 1); if(d == nil) error(Enodrawimage); return d->image; } void drawrectangle(Rectangle *r, uchar *a) { r->min.x = BGLONG(a+0*4); r->min.y = BGLONG(a+1*4); r->max.x = BGLONG(a+2*4); r->max.y = BGLONG(a+3*4); } void drawpoint(Point *p, uchar *a) { p->x = BGLONG(a+0*4); p->y = BGLONG(a+1*4); } #define isvgascreen(dst) 1 Point drawchar(Memimage *dst, Memimage *rdst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op) { FChar *fc; Rectangle r; Point sp1; static Memimage *tmp; fc = &font->fchar[index]; r.min.x = p.x+fc->left; r.min.y = p.y-(font->ascent-fc->miny); r.max.x = r.min.x+(fc->maxx-fc->minx); r.max.y = r.min.y+(fc->maxy-fc->miny); sp1.x = sp->x+fc->left; sp1.y = sp->y+fc->miny; /* * If we're drawing greyscale fonts onto a VGA screen, * it's very costly to read the screen memory to do the * alpha blending inside memdraw. If this is really a stringbg, * then rdst is the bg image (in main memory) which we can * refer to for the underlying dst pixels instead of reading dst * directly. */ if(1 || (isvgascreen(dst) && !isvgascreen(rdst) /*&& font->image->depth > 1*/)){ if(tmp == nil || tmp->chan != dst->chan || Dx(tmp->r) < Dx(r) || Dy(tmp->r) < Dy(r)){ if(tmp) freememimage(tmp); tmp = allocmemimage(Rect(0,0,Dx(r),Dy(r)), dst->chan); if(tmp == nil) goto fallback; } memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), rdst, r.min, memopaque, ZP, S); memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), src, sp1, font->image, Pt(fc->minx, fc->miny), op); memdraw(dst, r, tmp, ZP, memopaque, ZP, S); }else{ fallback: memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op); } p.x += fc->width; sp->x += fc->width; return p; } static int initscreenimage(void) { int width, depth; ulong chan; void *X; Rectangle r; if(screenimage != nil) return 1; screendata.base = nil; screendata.bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen, &X); if(screendata.bdata == nil && X == nil) return 0; screendata.ref = 1; screenimage = allocmemimaged(r, chan, &screendata, X); if(screenimage == nil){ /* RSC: BUG: detach screen */ return 0; } screenimage->width = width; screenimage->clipr = r; return 1; } void deletescreenimage(void) { qlock(&sdraw.lk); /* RSC: BUG: detach screen */ if(screenimage) freememimage(screenimage); screenimage = nil; qunlock(&sdraw.lk); } static Chan* drawattach(char *spec) { qlock(&sdraw.lk); if(!initscreenimage()){ qunlock(&sdraw.lk); error("no frame buffer"); } qunlock(&sdraw.lk); return devattach('i', spec); } static Walkqid* drawwalk(Chan *c, Chan *nc, char **name, int nname) { if(screendata.bdata == nil) error("no frame buffer"); return devwalk(c, nc, name, nname, 0, 0, drawgen); } static int drawstat(Chan *c, uchar *db, int n) { return devstat(c, db, n, 0, 0, drawgen); } static Chan* drawopen(Chan *c, int omode) { Client *cl; if(c->qid.type & QTDIR){ c = devopen(c, omode, 0, 0, drawgen); c->iounit = IOUNIT; } qlock(&sdraw.lk); if(waserror()){ qunlock(&sdraw.lk); nexterror(); } if(QID(c->qid) == Qnew){ cl = drawnewclient(); if(cl == 0) error(Enodev); c->qid.path = Qctl|((cl->slot+1)<qid)){ case Qnew: break; case Qctl: cl = drawclient(c); if(cl->busy) error(Einuse); cl->busy = 1; flushrect = Rect(10000, 10000, -10000, -10000); drawinstall(cl, 0, screenimage, 0); incref(&cl->r); break; case Qcolormap: case Qdata: case Qrefresh: cl = drawclient(c); incref(&cl->r); break; } qunlock(&sdraw.lk); poperror(); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; c->iounit = IOUNIT; return c; } static void drawclose(Chan *c) { int i; DImage *d, **dp; Client *cl; Refresh *r; if(QID(c->qid) < Qcolormap) /* Qtopdir, Qnew, Q3rd, Q2nd have no client */ return; qlock(&sdraw.lk); if(waserror()){ qunlock(&sdraw.lk); nexterror(); } cl = drawclient(c); if(QID(c->qid) == Qctl) cl->busy = 0; if((c->flag&COPEN) && (decref(&cl->r)==0)){ while((r = cl->refresh)){ /* assign = */ cl->refresh = r->next; free(r); } /* free names */ for(i=0; icscreen) drawuninstallscreen(cl, cl->cscreen); /* all screens are freed, so now we can free images */ dp = cl->dimage; for(i=0; inext; drawfreedimage(d); } dp++; } sdraw.client[cl->slot] = 0; drawflush(); /* to erase visible, now dead windows */ free(cl); } qunlock(&sdraw.lk); poperror(); } long drawread(Chan *c, void *a, long n, vlong off) { int index, m; ulong red, green, blue; Client *cl; uchar *p; Refresh *r; DImage *di; Memimage *i; ulong offset = off; char buf[16]; if(c->qid.type & QTDIR) return devdirread(c, a, n, 0, 0, drawgen); cl = drawclient(c); qlock(&sdraw.lk); if(waserror()){ qunlock(&sdraw.lk); nexterror(); } switch(QID(c->qid)){ case Qctl: if(n < 12*12) error(Eshortread); if(cl->infoid < 0) error(Enodrawimage); if(cl->infoid == 0){ i = screenimage; if(i == nil) error(Enodrawimage); }else{ di = drawlookup(cl, cl->infoid, 1); if(di == nil) error(Enodrawimage); i = di->image; } n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ", cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl, i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y, i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y); cl->infoid = -1; break; case Qcolormap: drawactive(1); /* to restore map from backup */ p = malloc(4*12*256+1); if(p == 0) error(Enomem); m = 0; for(index = 0; index < 256; index++){ getcolor(index, &red, &green, &blue); m += sprint((char*)p+m, "%11d %11lud %11lud %11lud\n", index, red>>24, green>>24, blue>>24); } n = readstr(offset, a, n, (char*)p); free(p); break; case Qdata: if(cl->readdata == nil) error("no draw data"); if(n < cl->nreaddata) error(Eshortread); n = cl->nreaddata; memmove(a, cl->readdata, cl->nreaddata); free(cl->readdata); cl->readdata = nil; break; case Qrefresh: if(n < 5*4) error(Ebadarg); for(;;){ if(cl->refreshme || cl->refresh) break; qunlock(&sdraw.lk); if(waserror()){ qlock(&sdraw.lk); /* restore lock for waserror() above */ nexterror(); } sleep(&cl->refrend, drawrefactive, cl); poperror(); qlock(&sdraw.lk); } p = a; while(cl->refresh && n>=5*4){ r = cl->refresh; BPLONG(p+0*4, r->dimage->id); BPLONG(p+1*4, r->r.min.x); BPLONG(p+2*4, r->r.min.y); BPLONG(p+3*4, r->r.max.x); BPLONG(p+4*4, r->r.max.y); cl->refresh = r->next; free(r); p += 5*4; n -= 5*4; } cl->refreshme = 0; n = p-(uchar*)a; } qunlock(&sdraw.lk); poperror(); return n; } void drawwakeall(void) { Client *cl; int i; for(i=0; irefreshme || cl->refresh)) wakeup(&cl->refrend); } } static long drawwrite(Chan *c, void *a, long n, vlong offset) { char buf[128], *fields[4], *q; Client *cl; int i, m, red, green, blue, x; USED(offset); if(c->qid.type & QTDIR) error(Eisdir); cl = drawclient(c); qlock(&sdraw.lk); if(waserror()){ drawwakeall(); qunlock(&sdraw.lk); nexterror(); } switch(QID(c->qid)){ case Qctl: if(n != 4) error("unknown draw control request"); cl->infoid = BGLONG((uchar*)a); break; case Qcolormap: drawactive(1); /* to restore map from backup */ m = n; n = 0; while(m > 0){ x = m; if(x > sizeof(buf)-1) x = sizeof(buf)-1; q = memccpy(buf, a, '\n', x); if(q == 0) break; i = q-buf; n += i; a = (char*)a + i; m -= i; *q = 0; if(tokenize(buf, fields, nelem(fields)) != 4) error(Ebadarg); i = strtoul(fields[0], 0, 0); red = strtoul(fields[1], 0, 0); green = strtoul(fields[2], 0, 0); blue = strtoul(fields[3], &q, 0); if(fields[3] == q) error(Ebadarg); if(red>255 || green>255 || blue>255 || i<0 || i>255) error(Ebadarg); red |= red<<8; red |= red<<16; green |= green<<8; green |= green<<16; blue |= blue<<8; blue |= blue<<16; setcolor(i, red, green, blue); } break; case Qdata: drawmesg(cl, a, n); drawwakeall(); break; default: error(Ebadusefd); } qunlock(&sdraw.lk); poperror(); return n; } uchar* drawcoord(uchar *p, uchar *maxp, int oldx, int *newx) { int b, x; if(p >= maxp) error(Eshortdraw); b = *p++; x = b & 0x7F; if(b & 0x80){ if(p+1 >= maxp) error(Eshortdraw); x |= *p++ << 7; x |= *p++ << 15; if(x & (1<<22)) x |= ~0<<23; }else{ if(b & 0x40) x |= ~0<<7; x += oldx; } *newx = x; return p; } static void printmesg(char *fmt, uchar *a, int plsprnt) { char buf[256]; char *p, *q; int s; if(1|| plsprnt==0){ SET(s); SET(q); SET(p); USED(fmt); USED(a); p = buf; USED(p); USED(q); USED(s); return; } q = buf; *q++ = *a++; for(p=fmt; *p; p++){ switch(*p){ case 'l': q += sprint(q, " %ld", (long)BGLONG(a)); a += 4; break; case 'L': q += sprint(q, " %.8lux", (ulong)BGLONG(a)); a += 4; break; case 'R': q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12)); a += 16; break; case 'P': q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4)); a += 8; break; case 'b': q += sprint(q, " %d", *a++); break; case 's': q += sprint(q, " %d", BGSHORT(a)); a += 2; break; case 'S': q += sprint(q, " %.4ux", BGSHORT(a)); a += 2; break; } } *q++ = '\n'; *q = 0; iprint("%.*s", (int)(q-buf), buf); } void drawmesg(Client *client, void *av, int n) { int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush; uchar *u, *a, refresh; char *fmt; ulong value, chan; Rectangle r, clipr; Point p, q, *pp, sp; Memimage *i, *dst, *src, *mask; Memimage *l, **lp; Memscreen *scrn; DImage *font, *ll, *di, *ddst, *dsrc; DName *dn; DScreen *dscrn; FChar *fc; Refx *refx; CScreen *cs; Refreshfn reffn; a = av; m = 0; fmt = nil; if(waserror()){ if(fmt) printmesg(fmt, a, 1); /* iprint("error: %s\n", up->errstr); */ nexterror(); } while((n-=m) > 0){ USED(fmt); a += m; switch(*a){ default: error("bad draw command"); /* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */ case 'b': printmesg(fmt="LLbLbRRL", a, 0); m = 1+4+4+1+4+1+4*4+4*4+4; if(n < m) error(Eshortdraw); dstid = BGLONG(a+1); scrnid = BGSHORT(a+5); refresh = a[9]; chan = BGLONG(a+10); repl = a[14]; drawrectangle(&r, a+15); drawrectangle(&clipr, a+31); value = BGLONG(a+47); if(drawlookup(client, dstid, 0)) error(Eimageexists); if(scrnid){ dscrn = drawlookupscreen(client, scrnid, &cs); scrn = dscrn->screen; if(repl || chan!=scrn->image->chan) error("image parameters incompatible with screen"); reffn = 0; switch(refresh){ case Refbackup: break; case Refnone: reffn = memlnorefresh; break; case Refmesg: reffn = drawrefresh; break; default: error("unknown refresh method"); } l = memlalloc(scrn, r, reffn, 0, value); if(l == 0) error(Edrawmem); addflush(l->layer->screenr); l->clipr = clipr; rectclip(&l->clipr, r); if(drawinstall(client, dstid, l, dscrn) == 0){ memldelete(l); error(Edrawmem); } dscrn->ref++; if(reffn){ refx = nil; if(reffn == drawrefresh){ refx = malloc(sizeof(Refx)); if(refx == 0){ drawuninstall(client, dstid); error(Edrawmem); } refx->client = client; refx->dimage = drawlookup(client, dstid, 1); } memlsetrefresh(l, reffn, refx); } continue; } i = allocmemimage(r, chan); if(i == 0) error(Edrawmem); if(repl) i->flags |= Frepl; i->clipr = clipr; if(!repl) rectclip(&i->clipr, r); if(drawinstall(client, dstid, i, 0) == 0){ freememimage(i); error(Edrawmem); } memfillcolor(i, value); continue; /* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */ case 'A': printmesg(fmt="LLLb", a, 1); m = 1+4+4+4+1; if(n < m) error(Eshortdraw); dstid = BGLONG(a+1); if(dstid == 0) error(Ebadarg); if(drawlookupdscreen(dstid)) error(Escreenexists); ddst = drawlookup(client, BGLONG(a+5), 1); dsrc = drawlookup(client, BGLONG(a+9), 1); if(ddst==0 || dsrc==0) error(Enodrawimage); if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0) error(Edrawmem); continue; /* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */ case 'c': printmesg(fmt="LbR", a, 0); m = 1+4+1+4*4; if(n < m) error(Eshortdraw); ddst = drawlookup(client, BGLONG(a+1), 1); if(ddst == nil) error(Enodrawimage); if(ddst->name) error("can't change repl/clipr of shared image"); dst = ddst->image; if(a[5]) dst->flags |= Frepl; drawrectangle(&dst->clipr, a+6); continue; /* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */ case 'd': printmesg(fmt="LLLRPP", a, 0); m = 1+4+4+4+4*4+2*4+2*4; if(n < m) error(Eshortdraw); dst = drawimage(client, a+1); dstid = BGLONG(a+1); src = drawimage(client, a+5); mask = drawimage(client, a+9); drawrectangle(&r, a+13); drawpoint(&p, a+29); drawpoint(&q, a+37); op = drawclientop(client); memdraw(dst, r, src, p, mask, q, op); dstflush(dstid, dst, r); continue; /* toggle debugging: 'D' val[1] */ case 'D': printmesg(fmt="b", a, 0); m = 1+1; if(n < m) error(Eshortdraw); drawdebug = a[1]; continue; /* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/ case 'e': case 'E': printmesg(fmt="LLPlllPll", a, 0); m = 1+4+4+2*4+4+4+4+2*4+2*4; if(n < m) error(Eshortdraw); dst = drawimage(client, a+1); dstid = BGLONG(a+1); src = drawimage(client, a+5); drawpoint(&p, a+9); e0 = BGLONG(a+17); e1 = BGLONG(a+21); if(e0<0 || e1<0) error("invalid ellipse semidiameter"); j = BGLONG(a+25); if(j < 0) error("negative ellipse thickness"); drawpoint(&sp, a+29); c = j; if(*a == 'E') c = -1; ox = BGLONG(a+37); oy = BGLONG(a+41); op = drawclientop(client); /* high bit indicates arc angles are present */ if(ox & (1U<<31)){ if((ox & (1<<30)) == 0) ox &= ~(1U<<31); memarc(dst, p, e0, e1, c, src, sp, ox, oy, op); }else memellipse(dst, p, e0, e1, c, src, sp, op); dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1)); continue; /* free: 'f' id[4] */ case 'f': printmesg(fmt="L", a, 1); m = 1+4; if(n < m) error(Eshortdraw); ll = drawlookup(client, BGLONG(a+1), 0); if(ll && ll->dscreen && ll->dscreen->owner != client) ll->dscreen->owner->refreshme = 1; drawuninstall(client, BGLONG(a+1)); continue; /* free screen: 'F' id[4] */ case 'F': printmesg(fmt="L", a, 1); m = 1+4; if(n < m) error(Eshortdraw); drawlookupscreen(client, BGLONG(a+1), &cs); drawuninstallscreen(client, cs); continue; /* initialize font: 'i' fontid[4] nchars[4] ascent[1] */ case 'i': printmesg(fmt="Llb", a, 1); m = 1+4+4+1; if(n < m) error(Eshortdraw); dstid = BGLONG(a+1); if(dstid == 0) error("can't use display as font"); font = drawlookup(client, dstid, 1); if(font == 0) error(Enodrawimage); if(font->image->layer) error("can't use window as font"); ni = BGLONG(a+5); if(ni<=0 || ni>4096) error("bad font size (4096 chars max)"); free(font->fchar); /* should we complain if non-zero? */ font->fchar = malloc(ni*sizeof(FChar)); if(font->fchar == 0) error("no memory for font"); memset(font->fchar, 0, ni*sizeof(FChar)); font->nfchar = ni; font->ascent = a[9]; continue; /* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */ case 'l': printmesg(fmt="LLSRPbb", a, 0); m = 1+4+4+2+4*4+2*4+1+1; if(n < m) error(Eshortdraw); font = drawlookup(client, BGLONG(a+1), 1); if(font == 0) error(Enodrawimage); if(font->nfchar == 0) error(Enotfont); src = drawimage(client, a+5); ci = BGSHORT(a+9); if(ci >= font->nfchar) error(Eindex); drawrectangle(&r, a+11); drawpoint(&p, a+27); memdraw(font->image, r, src, p, memopaque, p, S); fc = &font->fchar[ci]; fc->minx = r.min.x; fc->maxx = r.max.x; fc->miny = r.min.y; fc->maxy = r.max.y; fc->left = a[35]; fc->width = a[36]; continue; /* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */ case 'L': printmesg(fmt="LPPlllLP", a, 0); m = 1+4+2*4+2*4+4+4+4+4+2*4; if(n < m) error(Eshortdraw); dst = drawimage(client, a+1); dstid = BGLONG(a+1); drawpoint(&p, a+5); drawpoint(&q, a+13); e0 = BGLONG(a+21); e1 = BGLONG(a+25); j = BGLONG(a+29); if(j < 0) error("negative line width"); src = drawimage(client, a+33); drawpoint(&sp, a+37); op = drawclientop(client); memline(dst, p, q, e0, e1, j, src, sp, op); /* avoid memlinebbox if possible */ if(dstid==0 || dst->layer!=nil){ /* BUG: this is terribly inefficient: update maximal containing rect*/ r = memlinebbox(p, q, e0, e1, j); dstflush(dstid, dst, insetrect(r, -(1+1+j))); } continue; /* create image mask: 'm' newid[4] id[4] */ /* * case 'm': printmesg("LL", a, 0); m = 4+4; if(n < m) error(Eshortdraw); break; * */ /* attach to a named image: 'n' dstid[4] j[1] name[j] */ case 'n': printmesg(fmt="Lz", a, 0); m = 1+4+1; if(n < m) error(Eshortdraw); j = a[5]; if(j == 0) /* give me a non-empty name please */ error(Eshortdraw); m += j; if(n < m) error(Eshortdraw); dstid = BGLONG(a+1); if(drawlookup(client, dstid, 0)) error(Eimageexists); dn = drawlookupname(j, (char*)a+6); if(dn == nil) error(Enoname); if(drawinstall(client, dstid, dn->dimage->image, 0) == 0) error(Edrawmem); di = drawlookup(client, dstid, 0); if(di == 0) error("draw: can't happen"); di->vers = dn->vers; di->name = smalloc(j+1); di->fromname = dn->dimage; di->fromname->ref++; memmove(di->name, a+6, j); di->name[j] = 0; client->infoid = dstid; continue; /* name an image: 'N' dstid[4] in[1] j[1] name[j] */ case 'N': printmesg(fmt="Lbz", a, 0); m = 1+4+1+1; if(n < m) error(Eshortdraw); c = a[5]; j = a[6]; if(j == 0) /* give me a non-empty name please */ error(Eshortdraw); m += j; if(n < m) error(Eshortdraw); di = drawlookup(client, BGLONG(a+1), 0); if(di == 0) error(Enodrawimage); if(di->name) error(Enamed); if(c) drawaddname(client, di, j, (char*)a+7); else{ dn = drawlookupname(j, (char*)a+7); if(dn == nil) error(Enoname); if(dn->dimage != di) error(Ewrongname); drawdelname(dn); } continue; /* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */ case 'o': printmesg(fmt="LPP", a, 0); m = 1+4+2*4+2*4; if(n < m) error(Eshortdraw); dst = drawimage(client, a+1); if(dst->layer){ drawpoint(&p, a+5); drawpoint(&q, a+13); r = dst->layer->screenr; ni = memlorigin(dst, p, q); if(ni < 0) error("image origin failed"); if(ni > 0){ addflush(r); addflush(dst->layer->screenr); ll = drawlookup(client, BGLONG(a+1), 1); drawrefreshscreen(ll, client); } } continue; /* set compositing operator for next draw operation: 'O' op */ case 'O': printmesg(fmt="b", a, 0); m = 1+1; if(n < m) error(Eshortdraw); client->op = a[1]; continue; /* filled polygon: 'P' dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */ /* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */ case 'p': case 'P': printmesg(fmt="LslllLPP", a, 0); m = 1+4+2+4+4+4+4+2*4; if(n < m) error(Eshortdraw); dstid = BGLONG(a+1); dst = drawimage(client, a+1); ni = BGSHORT(a+5); if(ni < 0) error("negative count in polygon"); e0 = BGLONG(a+7); e1 = BGLONG(a+11); j = 0; if(*a == 'p'){ j = BGLONG(a+15); if(j < 0) error("negative polygon line width"); } src = drawimage(client, a+19); drawpoint(&sp, a+23); drawpoint(&p, a+31); ni++; pp = malloc(ni*sizeof(Point)); if(pp == nil) error(Enomem); doflush = 0; if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data)) doflush = 1; /* simplify test in loop */ ox = oy = 0; esize = 0; u = a+m; for(y=0; y esize) esize = c; } if(y == ni-1){ c = memlineendsize(e1); if(c > esize) esize = c; } } if(*a=='P' && e0!=1 && e0 !=~0) r = dst->clipr; else if(y > 0){ r = Rect(q.x-oesize, q.y-oesize, q.x+oesize+1, q.y+oesize+1); combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1)); } if(rectclip(&r, dst->clipr)) /* should perhaps be an arg to dstflush */ dstflush(dstid, dst, r); } pp[y] = p; } if(y == 1) dstflush(dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1)); op = drawclientop(client); if(*a == 'p') mempoly(dst, pp, ni, e0, e1, j, src, sp, op); else memfillpoly(dst, pp, ni, e0, src, sp, op); free(pp); m = u-a; continue; /* read: 'r' id[4] R[4*4] */ case 'r': printmesg(fmt="LR", a, 0); m = 1+4+4*4; if(n < m) error(Eshortdraw); i = drawimage(client, a+1); drawrectangle(&r, a+5); if(!rectinrect(r, i->r)) error(Ereadoutside); c = bytesperline(r, i->depth); c *= Dy(r); free(client->readdata); client->readdata = mallocz(c, 0); if(client->readdata == nil) error("readimage malloc failed"); client->nreaddata = memunload(i, r, client->readdata, c); if(client->nreaddata < 0){ free(client->readdata); client->readdata = nil; error("bad readimage call"); } continue; /* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */ /* stringbg: 'x' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] bgid[4] bgpt[2*4] ni*(index[2]) */ case 's': case 'x': printmesg(fmt="LLLPRPs", a, 0); m = 1+4+4+4+2*4+4*4+2*4+2; if(*a == 'x') m += 4+2*4; if(n < m) error(Eshortdraw); dst = drawimage(client, a+1); dstid = BGLONG(a+1); src = drawimage(client, a+5); font = drawlookup(client, BGLONG(a+9), 1); if(font == 0) error(Enodrawimage); if(font->nfchar == 0) error(Enotfont); drawpoint(&p, a+13); drawrectangle(&r, a+21); drawpoint(&sp, a+37); ni = BGSHORT(a+45); u = a+m; m += ni*2; if(n < m) error(Eshortdraw); clipr = dst->clipr; dst->clipr = r; op = drawclientop(client); l = dst; if(*a == 'x'){ /* paint background */ l = drawimage(client, a+47); drawpoint(&q, a+51); r.min.x = p.x; r.min.y = p.y-font->ascent; r.max.x = p.x; r.max.y = r.min.y+Dy(font->image->r); j = ni; while(--j >= 0){ ci = BGSHORT(u); if(ci<0 || ci>=font->nfchar){ dst->clipr = clipr; error(Eindex); } r.max.x += font->fchar[ci].width; u += 2; } memdraw(dst, r, l, q, memopaque, ZP, op); u -= 2*ni; } q = p; while(--ni >= 0){ ci = BGSHORT(u); if(ci<0 || ci>=font->nfchar){ dst->clipr = clipr; error(Eindex); } q = drawchar(dst, l, q, src, &sp, font, ci, op); u += 2; } dst->clipr = clipr; p.y -= font->ascent; dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r))); continue; /* use public screen: 'S' id[4] chan[4] */ case 'S': printmesg(fmt="Ll", a, 0); m = 1+4+4; if(n < m) error(Eshortdraw); dstid = BGLONG(a+1); if(dstid == 0) error(Ebadarg); dscrn = drawlookupdscreen(dstid); if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client)) error(Enodrawscreen); if(dscrn->screen->image->chan != BGLONG(a+5)) error("inconsistent chan"); if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0) error(Edrawmem); continue; /* top or bottom windows: 't' top[1] nw[2] n*id[4] */ case 't': printmesg(fmt="bsL", a, 0); m = 1+1+2; if(n < m) error(Eshortdraw); nw = BGSHORT(a+2); if(nw < 0) error(Ebadarg); if(nw == 0) continue; m += nw*4; if(n < m) error(Eshortdraw); lp = malloc(nw*sizeof(Memimage*)); if(lp == 0) error(Enomem); if(waserror()){ free(lp); nexterror(); } for(j=0; jlayer == 0) error("images are not windows"); for(j=1; jlayer->screen != lp[0]->layer->screen) error("images not on same screen"); if(a[1]) memltofrontn(lp, nw); else memltorearn(lp, nw); if(lp[0]->layer->screen->image->data == screenimage->data) for(j=0; jlayer->screenr); ll = drawlookup(client, BGLONG(a+1+1+2), 1); drawrefreshscreen(ll, client); poperror(); free(lp); continue; /* visible: 'v' */ case 'v': printmesg(fmt="", a, 0); m = 1; drawflush(); continue; /* write: 'y' id[4] R[4*4] data[x*1] */ /* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */ case 'y': case 'Y': printmesg(fmt="LR", a, 0); // iprint("load %c\n", *a); m = 1+4+4*4; if(n < m) error(Eshortdraw); dstid = BGLONG(a+1); dst = drawimage(client, a+1); drawrectangle(&r, a+5); if(!rectinrect(r, dst->r)) error(Ewriteoutside); y = memload(dst, r, a+m, n-m, *a=='Y'); if(y < 0) error("bad writeimage call"); dstflush(dstid, dst, r); m += y; continue; } } poperror(); } Dev drawdevtab = { 'i', "draw", devreset, devinit, devshutdown, drawattach, drawwalk, drawstat, drawopen, devcreate, drawclose, drawread, devbread, drawwrite, devbwrite, devremove, devwstat, }; /* * On 8 bit displays, load the default color map */ void drawcmap(void) { int r, g, b, cr, cg, cb, v; int num, den; int i, j; drawactive(1); /* to restore map from backup */ for(r=0,i=0; r!=4; r++) for(v=0; v!=4; v++,i+=16){ for(g=0,j=v-r; g!=4; g++) for(b=0;b!=4;b++,j++){ den = r; if(g > den) den = g; if(b > den) den = b; if(den == 0) /* divide check -- pick grey shades */ cr = cg = cb = v*17; else{ num = 17*(4*den+v); cr = r*num/den; cg = g*num/den; cb = b*num/den; } setcolor(i+(j&15), cr*0x01010101, cg*0x01010101, cb*0x01010101); } } } void drawblankscreen(int blank) { int i, nc; ulong *p; if(blank == sdraw.blanked) return; if(!canqlock(&sdraw.lk)) return; if(!initscreenimage()){ qunlock(&sdraw.lk); return; } p = sdraw.savemap; nc = screenimage->depth > 8 ? 256 : 1<depth; /* * blankscreen uses the hardware to blank the screen * when possible. to help in cases when it is not possible, * we set the color map to be all black. */ if(blank == 0){ /* turn screen on */ for(i=0; iticks; }else{ if(blanktime && sdraw.blanktime && TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60 >= blanktime) drawblankscreen(1); } */ } int drawidletime(void) { return 0; /* return TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60; */ } drawterm-20170818/kern/devfs-posix.c000066400000000000000000000230331314554504700171760ustar00rootroot00000000000000#include "u.h" #include #include #include #include #include #include /* for remove, rename */ #include #ifndef NAME_MAX # define NAME_MAX 256 #endif #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" typedef struct Ufsinfo Ufsinfo; enum { NUID = 256, NGID = 256, MAXPATH = 1024, MAXCOMP = 128 }; struct Ufsinfo { int mode; int fd; int uid; int gid; DIR* dir; vlong offset; QLock oq; char nextname[NAME_MAX]; }; char *base = "/"; static Qid fsqid(char*, struct stat *); static void fspath(Chan*, char*, char*); static ulong fsdirread(Chan*, uchar*, int, ulong); static int fsomode(int); /* clumsy hack, but not worse than the Path stuff in the last one */ static char* uc2name(Chan *c) { char *s; if(c->name == nil) return "/"; s = c2name(c); if(s[0]=='#' && s[1]=='U') return s+2; return s; } static char* lastelem(Chan *c) { char *s, *t; s = uc2name(c); if((t = strrchr(s, '/')) == nil) return s; if(t[1] == 0) return t; return t+1; } static Chan* fsattach(char *spec) { Chan *c; struct stat stbuf; static int devno; Ufsinfo *uif; if(stat(base, &stbuf) < 0) error(strerror(errno)); c = devattach('U', spec); uif = mallocz(sizeof(Ufsinfo), 1); uif->mode = stbuf.st_mode; uif->uid = stbuf.st_uid; uif->gid = stbuf.st_gid; c->aux = uif; c->dev = devno++; c->qid.type = QTDIR; /*print("fsattach %s\n", c2name(c));*/ return c; } static Chan* fsclone(Chan *c, Chan *nc) { Ufsinfo *uif; uif = mallocz(sizeof(Ufsinfo), 1); *uif = *(Ufsinfo*)c->aux; nc->aux = uif; return nc; } static int fswalk1(Chan *c, char *name) { struct stat stbuf; char path[MAXPATH]; Ufsinfo *uif; fspath(c, name, path); /*print("** fs walk '%s' -> %s\n", path, name); */ if(stat(path, &stbuf) < 0) return 0; uif = c->aux; uif->mode = stbuf.st_mode; uif->uid = stbuf.st_uid; uif->gid = stbuf.st_gid; c->qid = fsqid(path, &stbuf); return 1; } extern Cname* addelem(Cname*, char*); static Walkqid* fswalk(Chan *c, Chan *nc, char **name, int nname) { int i; Cname *cname; Walkqid *wq; if(nc != nil) panic("fswalk: nc != nil"); wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); nc = devclone(c); cname = c->name; incref(&cname->ref); fsclone(c, nc); wq->clone = nc; for(i=0; iname = cname; if(fswalk1(nc, name[i]) == 0) break; cname = addelem(cname, name[i]); wq->qid[i] = nc->qid; } nc->name = cname; if(i != nname){ cclose(nc); wq->clone = nil; } wq->nqid = i; return wq; } static int fsstat(Chan *c, uchar *buf, int n) { Dir d; struct stat stbuf; char path[MAXPATH]; if(n < BIT16SZ) error(Eshortstat); fspath(c, 0, path); if(stat(path, &stbuf) < 0) error(strerror(errno)); d.name = lastelem(c); d.uid = "unknown"; d.gid = "unknown"; d.muid = "unknown"; d.qid = c->qid; d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777); d.atime = stbuf.st_atime; d.mtime = stbuf.st_mtime; d.length = stbuf.st_size; d.type = 'U'; d.dev = c->dev; return convD2M(&d, buf, n); } static Chan* fsopen(Chan *c, int mode) { char path[MAXPATH]; int m, isdir; Ufsinfo *uif; /*print("fsopen %s\n", c2name(c));*/ m = mode & (OTRUNC|3); switch(m) { case 0: break; case 1: case 1|16: break; case 2: case 0|16: case 2|16: break; case 3: break; default: error(Ebadarg); } isdir = c->qid.type & QTDIR; if(isdir && mode != OREAD) error(Eperm); m = fsomode(m & 3); c->mode = openmode(mode); uif = c->aux; fspath(c, 0, path); if(isdir) { uif->dir = opendir(path); if(uif->dir == 0) error(strerror(errno)); } else { if(mode & OTRUNC) m |= O_TRUNC; uif->fd = open(path, m, 0666); if(uif->fd < 0) error(strerror(errno)); } uif->offset = 0; c->offset = 0; c->flag |= COPEN; return c; } static void fscreate(Chan *c, char *name, int mode, ulong perm) { int fd, m; char path[MAXPATH]; struct stat stbuf; Ufsinfo *uif; m = fsomode(mode&3); fspath(c, name, path); uif = c->aux; if(perm & DMDIR) { if(m) error(Eperm); if(mkdir(path, perm & 0777) < 0) error(strerror(errno)); fd = open(path, 0); if(fd >= 0) { chmod(path, perm & 0777); chown(path, uif->uid, uif->uid); } close(fd); uif->dir = opendir(path); if(uif->dir == 0) error(strerror(errno)); } else { fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666); if(fd >= 0) { if(m != 1) { close(fd); fd = open(path, m); } chmod(path, perm & 0777); chown(path, uif->uid, uif->gid); } if(fd < 0) error(strerror(errno)); uif->fd = fd; } if(stat(path, &stbuf) < 0) error(strerror(errno)); c->qid = fsqid(path, &stbuf); c->offset = 0; c->flag |= COPEN; c->mode = openmode(mode); } static void fsclose(Chan *c) { Ufsinfo *uif; uif = c->aux; if(c->flag & COPEN) { if(c->qid.type & QTDIR) closedir(uif->dir); else close(uif->fd); } free(uif); } static long fsread(Chan *c, void *va, long n, vlong offset) { int fd, r; Ufsinfo *uif; /*print("fsread %s\n", c2name(c));*/ if(c->qid.type & QTDIR) return fsdirread(c, va, n, offset); uif = c->aux; qlock(&uif->oq); if(waserror()) { qunlock(&uif->oq); nexterror(); } fd = uif->fd; if(uif->offset != offset) { r = lseek(fd, offset, 0); if(r < 0) error(strerror(errno)); uif->offset = offset; } n = read(fd, va, n); if(n < 0) error(strerror(errno)); uif->offset += n; qunlock(&uif->oq); poperror(); return n; } static long fswrite(Chan *c, void *va, long n, vlong offset) { int fd, r; Ufsinfo *uif; uif = c->aux; qlock(&uif->oq); if(waserror()) { qunlock(&uif->oq); nexterror(); } fd = uif->fd; if(uif->offset != offset) { r = lseek(fd, offset, 0); if(r < 0) error(strerror(errno)); uif->offset = offset; } n = write(fd, va, n); if(n < 0) error(strerror(errno)); uif->offset += n; qunlock(&uif->oq); poperror(); return n; } static void fsremove(Chan *c) { int n; char path[MAXPATH]; fspath(c, 0, path); if(c->qid.type & QTDIR) n = rmdir(path); else n = remove(path); if(n < 0) error(strerror(errno)); } int fswstat(Chan *c, uchar *buf, int n) { Dir d; struct stat stbuf; char old[MAXPATH], new[MAXPATH]; char strs[MAXPATH*3], *p; Ufsinfo *uif; if(convM2D(buf, n, &d, strs) != n) error(Ebadstat); fspath(c, 0, old); if(stat(old, &stbuf) < 0) error(strerror(errno)); uif = c->aux; fspath(c, 0, old); if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) { if(chmod(old, d.mode&0777) < 0) error(strerror(errno)); uif->mode &= ~0777; uif->mode |= d.mode&0777; } if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) { fspath(c, 0, old); strcpy(new, old); p = strrchr(new, '/'); strcpy(p+1, d.name); if(rename(old, new) < 0) error(strerror(errno)); } /* p = name2pass(gid, d.gid); if(p == 0) error(Eunknown); if(p->id != stbuf.st_gid) { if(chown(old, stbuf.st_uid, p->id) < 0) error(strerror(errno)); uif->gid = p->id; } */ return n; } static Qid fsqid(char *p, struct stat *st) { Qid q; int dev; ulong h; static int nqdev; static uchar *qdev; if(qdev == 0) qdev = mallocz(65536U, 1); q.type = 0; if((st->st_mode&S_IFMT) == S_IFDIR) q.type = QTDIR; dev = st->st_dev & 0xFFFFUL; if(qdev[dev] == 0) qdev[dev] = ++nqdev; h = 0; while(*p != '\0') h += *p++ * 13; q.path = (vlong)qdev[dev]<<32; q.path |= h; q.vers = st->st_mtime; return q; } static void fspath(Chan *c, char *ext, char *path) { strcpy(path, base); strcat(path, "/"); strcat(path, uc2name(c)); if(ext){ strcat(path, "/"); strcat(path, ext); } cleanname(path); } static int isdots(char *name) { if(name[0] != '.') return 0; if(name[1] == '\0') return 1; if(name[1] != '.') return 0; if(name[2] == '\0') return 1; return 0; } static int p9readdir(char *name, Ufsinfo *uif) { struct dirent *de; if(uif->nextname[0]){ strcpy(name, uif->nextname); uif->nextname[0] = 0; return 1; } de = readdir(uif->dir); if(de == NULL) return 0; strcpy(name, de->d_name); return 1; } static ulong fsdirread(Chan *c, uchar *va, int count, ulong offset) { int i; Dir d; long n; char de[NAME_MAX]; struct stat stbuf; char path[MAXPATH], dirpath[MAXPATH]; Ufsinfo *uif; /*print("fsdirread %s\n", c2name(c));*/ i = 0; uif = c->aux; errno = 0; if(uif->offset != offset) { if(offset != 0) error("bad offset in fsdirread"); uif->offset = offset; /* sync offset */ uif->nextname[0] = 0; rewinddir(uif->dir); } fspath(c, 0, dirpath); while(i+BIT16SZ < count) { if(!p9readdir(de, uif)) break; if(de[0]==0 || isdots(de)) continue; d.name = de; sprint(path, "%s/%s", dirpath, de); memset(&stbuf, 0, sizeof stbuf); if(stat(path, &stbuf) < 0) { /* fprint(2, "dir: bad path %s\n", path); */ /* but continue... probably a bad symlink */ } d.uid = "unknown"; d.gid = "unknown"; d.muid = "unknown"; d.qid = fsqid(path, &stbuf); d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777); d.atime = stbuf.st_atime; d.mtime = stbuf.st_mtime; d.length = stbuf.st_size; d.type = 'U'; d.dev = c->dev; n = convD2M(&d, (uchar*)va+i, count-i); if(n == BIT16SZ){ strcpy(uif->nextname, de); break; } i += n; } /*print("got %d\n", i);*/ uif->offset += i; return i; } static int fsomode(int m) { switch(m) { case 0: /* OREAD */ case 3: /* OEXEC */ return 0; case 1: /* OWRITE */ return 1; case 2: /* ORDWR */ return 2; } error(Ebadarg); return 0; } Dev fsdevtab = { 'U', "fs", devreset, devinit, devshutdown, fsattach, fswalk, fsstat, fsopen, fscreate, fsclose, fsread, devbread, fswrite, devbwrite, fsremove, fswstat, }; drawterm-20170818/kern/devfs-win32.c000066400000000000000000000251251314554504700170020ustar00rootroot00000000000000/* * Disable Unicode until the calls to FindFirstFile etc * are changed to use wide character strings. */ #undef UNICODE #include #include #include #include #ifndef NAME_MAX # define NAME_MAX 256 #endif #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" typedef struct DIR DIR; typedef struct Ufsinfo Ufsinfo; enum { NUID = 256, NGID = 256, MAXPATH = 1024, MAXCOMP = 128 }; struct DIR { HANDLE handle; char* path; int index; WIN32_FIND_DATA wfd; }; struct Ufsinfo { int mode; int fd; int uid; int gid; DIR* dir; ulong offset; QLock oq; char nextname[NAME_MAX]; }; DIR* opendir(char*); int readdir(char*, DIR*); void closedir(DIR*); void rewinddir(DIR*); char *base = "c:/."; static Qid fsqid(char*, struct stat *); static void fspath(Chan*, char*, char*); // static void fsperm(Chan*, int); static ulong fsdirread(Chan*, uchar*, int, ulong); static int fsomode(int); static int chown(char *path, int uid, int); /* clumsy hack, but not worse than the Path stuff in the last one */ static char* uc2name(Chan *c) { char *s; if(c->name == nil) return "/"; s = c2name(c); if(s[0]=='#' && s[1]=='U') return s+2; return s; } static char* lastelem(Chan *c) { char *s, *t; s = uc2name(c); if((t = strrchr(s, '/')) == nil) return s; if(t[1] == 0) return t; return t+1; } static Chan* fsattach(char *spec) { Chan *c; struct stat stbuf; static int devno; Ufsinfo *uif; if(stat(base, &stbuf) < 0) error(strerror(errno)); c = devattach('U', spec); uif = mallocz(sizeof(Ufsinfo), 1); uif->gid = stbuf.st_gid; uif->uid = stbuf.st_uid; uif->mode = stbuf.st_mode; c->aux = uif; c->dev = devno++; c->qid.type = QTDIR; /*print("fsattach %s\n", c2name(c));*/ return c; } static Chan* fsclone(Chan *c, Chan *nc) { Ufsinfo *uif; uif = mallocz(sizeof(Ufsinfo), 1); *uif = *(Ufsinfo*)c->aux; nc->aux = uif; return nc; } static int fswalk1(Chan *c, char *name) { struct stat stbuf; char path[MAXPATH]; Ufsinfo *uif; fspath(c, name, path); /* print("** fs walk '%s' -> %s\n", path, name); */ if(stat(path, &stbuf) < 0) return 0; uif = c->aux; uif->gid = stbuf.st_gid; uif->uid = stbuf.st_uid; uif->mode = stbuf.st_mode; c->qid = fsqid(path, &stbuf); return 1; } extern Cname* addelem(Cname*, char*); static Walkqid* fswalk(Chan *c, Chan *nc, char **name, int nname) { int i; Cname *cname; Walkqid *wq; if(nc != nil) panic("fswalk: nc != nil"); wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); nc = devclone(c); cname = c->name; incref(&cname->ref); fsclone(c, nc); wq->clone = nc; for(i=0; iname = cname; if(fswalk1(nc, name[i]) == 0) break; cname = addelem(cname, name[i]); wq->qid[i] = nc->qid; } nc->name = cname; if(i != nname){ cclose(nc); wq->clone = nil; } wq->nqid = i; return wq; } static int fsstat(Chan *c, uchar *buf, int n) { Dir d; struct stat stbuf; char path[MAXPATH]; if(n < BIT16SZ) error(Eshortstat); fspath(c, 0, path); if(stat(path, &stbuf) < 0) error(strerror(errno)); d.name = lastelem(c); d.uid = "unknown"; d.gid = "unknown"; d.muid = "unknown"; d.qid = c->qid; d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777); d.atime = stbuf.st_atime; d.mtime = stbuf.st_mtime; d.length = stbuf.st_size; d.type = 'U'; d.dev = c->dev; return convD2M(&d, buf, n); } static Chan* fsopen(Chan *c, int mode) { char path[MAXPATH]; int m, isdir; Ufsinfo *uif; /*print("fsopen %s\n", c2name(c));*/ m = mode & (OTRUNC|3); switch(m) { case 0: break; case 1: case 1|16: break; case 2: case 0|16: case 2|16: break; case 3: break; default: error(Ebadarg); } isdir = c->qid.type & QTDIR; if(isdir && mode != OREAD) error(Eperm); m = fsomode(m & 3); c->mode = openmode(mode); uif = c->aux; fspath(c, 0, path); if(isdir) { uif->dir = opendir(path); if(uif->dir == 0) error(strerror(errno)); } else { if(mode & OTRUNC) m |= O_TRUNC; uif->fd = open(path, m|_O_BINARY, 0666); if(uif->fd < 0) error(strerror(errno)); } uif->offset = 0; c->offset = 0; c->flag |= COPEN; return c; } static void fscreate(Chan *c, char *name, int mode, ulong perm) { int fd, m; char path[MAXPATH]; struct stat stbuf; Ufsinfo *uif; m = fsomode(mode&3); fspath(c, name, path); uif = c->aux; if(perm & DMDIR) { if(m) error(Eperm); if(mkdir(path) < 0) error(strerror(errno)); fd = open(path, 0); if(fd >= 0) { chmod(path, perm & 0777); chown(path, uif->uid, uif->uid); } close(fd); uif->dir = opendir(path); if(uif->dir == 0) error(strerror(errno)); } else { fd = open(path, _O_WRONLY|_O_BINARY|_O_CREAT|_O_TRUNC, 0666); if(fd >= 0) { if(m != 1) { close(fd); fd = open(path, m|_O_BINARY); } chmod(path, perm & 0777); chown(path, uif->uid, uif->gid); } if(fd < 0) error(strerror(errno)); uif->fd = fd; } if(stat(path, &stbuf) < 0) error(strerror(errno)); c->qid = fsqid(path, &stbuf); c->offset = 0; c->flag |= COPEN; c->mode = openmode(mode); } static void fsclose(Chan *c) { Ufsinfo *uif; uif = c->aux; if(c->flag & COPEN) { if(c->qid.type & QTDIR) closedir(uif->dir); else close(uif->fd); } free(uif); } static long fsread(Chan *c, void *va, long n, vlong offset) { int fd, r; Ufsinfo *uif; /*print("fsread %s\n", c2name(c));*/ if(c->qid.type & QTDIR) return fsdirread(c, va, n, offset); uif = c->aux; qlock(&uif->oq); if(waserror()) { qunlock(&uif->oq); nexterror(); } fd = uif->fd; if(uif->offset != offset) { r = lseek(fd, offset, 0); if(r < 0) error(strerror(errno)); uif->offset = offset; } n = read(fd, va, n); if(n < 0) error(strerror(errno)); uif->offset += n; qunlock(&uif->oq); poperror(); return n; } static long fswrite(Chan *c, void *va, long n, vlong offset) { int fd, r; Ufsinfo *uif; uif = c->aux; qlock(&uif->oq); if(waserror()) { qunlock(&uif->oq); nexterror(); } fd = uif->fd; if(uif->offset != offset) { r = lseek(fd, offset, 0); if(r < 0) error(strerror(errno)); uif->offset = offset; } n = write(fd, va, n); if(n < 0) error(strerror(errno)); uif->offset += n; qunlock(&uif->oq); poperror(); return n; } static void fsremove(Chan *c) { int n; char path[MAXPATH]; fspath(c, 0, path); if(c->qid.type & QTDIR) n = rmdir(path); else n = remove(path); if(n < 0) error(strerror(errno)); } static int fswstat(Chan *c, uchar *buf, int n) { Dir d; struct stat stbuf; char old[MAXPATH], new[MAXPATH]; char strs[MAXPATH*3], *p; Ufsinfo *uif; if (convM2D(buf, n, &d, strs) != n) error(Ebadstat); fspath(c, 0, old); if(stat(old, &stbuf) < 0) error(strerror(errno)); uif = c->aux; // if(uif->uid != stbuf.st_uid) // error(Eowner); if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) { fspath(c, 0, old); strcpy(new, old); p = strrchr(new, '/'); strcpy(p+1, d.name); if(rename(old, new) < 0) error(strerror(errno)); } fspath(c, 0, old); if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) { if(chmod(old, d.mode&0777) < 0) error(strerror(errno)); uif->mode &= ~0777; uif->mode |= d.mode&0777; } /* p = name2pass(gid, d.gid); if(p == 0) error(Eunknown); if(p->id != stbuf.st_gid) { if(chown(old, stbuf.st_uid, p->id) < 0) error(sys_errlist[errno]); uif->gid = p->id; } */ return n; } static Qid fsqid(char *p, struct stat *st) { Qid q; int dev; ulong h; static int nqdev; static uchar *qdev; if(qdev == 0) qdev = mallocz(65536U, 1); q.type = 0; if((st->st_mode&S_IFMT) == S_IFDIR) q.type = QTDIR; dev = st->st_dev & 0xFFFFUL; if(qdev[dev] == 0) qdev[dev] = ++nqdev; h = 0; while(*p != '\0') h += *p++ * 13; q.path = (vlong)qdev[dev]<<32; q.path |= h; q.vers = st->st_mtime; return q; } static void fspath(Chan *c, char *ext, char *path) { strcpy(path, base); strcat(path, "/"); strcat(path, uc2name(c)); if(ext) { strcat(path, "/"); strcat(path, ext); } cleanname(path); } static int isdots(char *name) { if(name[0] != '.') return 0; if(name[1] == '\0') return 1; if(name[1] != '.') return 0; if(name[2] == '\0') return 1; return 0; } static int p9readdir(char *name, Ufsinfo *uif) { if(uif->nextname[0]){ strcpy(name, uif->nextname); uif->nextname[0] = 0; return 1; } return readdir(name, uif->dir); } static ulong fsdirread(Chan *c, uchar *va, int count, ulong offset) { int i; Dir d; long n; char de[NAME_MAX]; struct stat stbuf; char path[MAXPATH], dirpath[MAXPATH]; Ufsinfo *uif; /*print("fsdirread %s\n", c2name(c));*/ i = 0; uif = c->aux; errno = 0; if(uif->offset != offset) { if(offset != 0) error("bad offset in fsdirread"); uif->offset = offset; /* sync offset */ uif->nextname[0] = 0; rewinddir(uif->dir); } fspath(c, 0, dirpath); while(i+BIT16SZ < count) { if(!p9readdir(de, uif)) break; if(de[0]==0 || isdots(de)) continue; d.name = de; sprint(path, "%s/%s", dirpath, de); memset(&stbuf, 0, sizeof stbuf); if(stat(path, &stbuf) < 0) { print("dir: bad path %s\n", path); /* but continue... probably a bad symlink */ } d.uid = "unknown"; d.gid = "unknown"; d.muid = "unknown"; d.qid = fsqid(path, &stbuf); d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777); d.atime = stbuf.st_atime; d.mtime = stbuf.st_mtime; d.length = stbuf.st_size; d.type = 'U'; d.dev = c->dev; n = convD2M(&d, (uchar*)va+i, count-i); if(n == BIT16SZ){ strcpy(uif->nextname, de); break; } i += n; } /*print("got %d\n", i);*/ uif->offset += i; return i; } static int fsomode(int m) { switch(m) { case 0: /* OREAD */ case 3: /* OEXEC */ return 0; case 1: /* OWRITE */ return 1; case 2: /* ORDWR */ return 2; } error(Ebadarg); return 0; } void closedir(DIR *d) { FindClose(d->handle); free(d->path); } int readdir(char *name, DIR *d) { if(d->index != 0) { if(FindNextFile(d->handle, &d->wfd) == FALSE) return 0; } strcpy(name, (char*)d->wfd.cFileName); d->index++; return 1; } void rewinddir(DIR *d) { FindClose(d->handle); d->handle = FindFirstFile(d->path, &d->wfd); d->index = 0; } static int chown(char *path, int uid, int perm) { /* panic("chown"); */ return 0; } DIR* opendir(char *p) { DIR *d; char path[MAX_PATH]; snprint(path, sizeof(path), "%s/*.*", p); d = mallocz(sizeof(DIR), 1); if(d == 0) return 0; d->index = 0; d->handle = FindFirstFile(path, &d->wfd); if(d->handle == INVALID_HANDLE_VALUE) { free(d); return 0; } d->path = strdup(path); return d; } Dev fsdevtab = { 'U', "fs", devreset, devinit, devshutdown, fsattach, fswalk, fsstat, fsopen, fscreate, fsclose, fsread, devbread, fswrite, devbwrite, fsremove, fswstat, }; drawterm-20170818/kern/devip-posix.c000066400000000000000000000124311314554504700171760ustar00rootroot00000000000000#include #include #include #include #include #include #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "ip.h" #include "devip.h" #undef listen #undef accept #undef bind static int family(unsigned char *addr) { if(isv4(addr)) return AF_INET; return AF_INET6; } static int addrlen(struct sockaddr_storage *ss) { switch(ss->ss_family){ case AF_INET: return sizeof(struct sockaddr_in); case AF_INET6: return sizeof(struct sockaddr_in6); } return 0; } void osipinit(void) { char buf[1024]; gethostname(buf, sizeof(buf)); kstrdup(&sysname, buf); } int so_socket(int type, unsigned char *addr) { int fd, one; switch(type) { default: error("bad protocol type"); case S_TCP: type = SOCK_STREAM; break; case S_UDP: type = SOCK_DGRAM; break; } fd = socket(family(addr), type, 0); if(fd < 0) oserror(); one = 1; if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0){ oserrstr(); print("setsockopt: %r"); } return fd; } void so_connect(int fd, unsigned char *raddr, unsigned short rport) { struct sockaddr_storage ss; memset(&ss, 0, sizeof(ss)); ss.ss_family = family(raddr); switch(ss.ss_family){ case AF_INET: hnputs(&((struct sockaddr_in*)&ss)->sin_port, rport); v6tov4((unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr, raddr); break; case AF_INET6: hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, rport); memcpy(&((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, raddr, sizeof(struct in6_addr)); break; } if(connect(fd, (struct sockaddr*)&ss, addrlen(&ss)) < 0) oserror(); } void so_getsockname(int fd, unsigned char *laddr, unsigned short *lport) { socklen_t len; struct sockaddr_storage ss; len = sizeof(ss); if(getsockname(fd, (struct sockaddr*)&ss, &len) < 0) oserror(); switch(ss.ss_family){ case AF_INET: v4tov6(laddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr); *lport = nhgets(&((struct sockaddr_in*)&ss)->sin_port); break; case AF_INET6: memcpy(laddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr)); *lport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port); break; default: error("not AF_INET or AF_INET6"); } } void so_listen(int fd) { if(listen(fd, 5) < 0) oserror(); } int so_accept(int fd, unsigned char *raddr, unsigned short *rport) { int nfd; socklen_t len; struct sockaddr_storage ss; len = sizeof(ss); nfd = accept(fd, (struct sockaddr*)&ss, &len); if(nfd < 0) oserror(); switch(ss.ss_family){ case AF_INET: v4tov6(raddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr); *rport = nhgets(&((struct sockaddr_in*)&ss)->sin_port); break; case AF_INET6: memcpy(raddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr)); *rport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port); break; default: error("not AF_INET or AF_INET6"); } return nfd; } void so_bind(int fd, int su, unsigned short port, unsigned char *addr) { int i, one; struct sockaddr_storage ss; one = 1; if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0){ oserrstr(); print("setsockopt: %r"); } if(su) { for(i = 600; i < 1024; i++) { memset(&ss, 0, sizeof(ss)); ss.ss_family = family(addr); switch(ss.ss_family){ case AF_INET: ((struct sockaddr_in*)&ss)->sin_port = i; break; case AF_INET6: ((struct sockaddr_in6*)&ss)->sin6_port = i; break; } if(bind(fd, (struct sockaddr*)&ss, addrlen(&ss)) >= 0) return; } oserror(); } memset(&ss, 0, sizeof(ss)); ss.ss_family = family(addr); switch(ss.ss_family){ case AF_INET: hnputs(&((struct sockaddr_in*)&ss)->sin_port, port); break; case AF_INET6: hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, port); break; } if(bind(fd, (struct sockaddr*)&ss, addrlen(&ss)) < 0) oserror(); } int so_gethostbyname(char *host, char**hostv, int n) { int i; char buf[32]; unsigned char *p; struct hostent *hp; hp = gethostbyname(host); if(hp == 0) return 0; for(i = 0; hp->h_addr_list[i] && i < n; i++) { p = (unsigned char*)hp->h_addr_list[i]; sprint(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); hostv[i] = strdup(buf); if(hostv[i] == 0) break; } return i; } char* hostlookup(char *host) { char buf[INET6_ADDRSTRLEN]; uchar *p; struct hostent *he; struct addrinfo *result; he = gethostbyname(host); if(he != 0 && he->h_addr_list[0]) { p = (uchar*)he->h_addr_list[0]; sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]); } else if(getaddrinfo(host, NULL, NULL, &result) == 0) { switch (result->ai_family) { case AF_INET: inet_ntop(AF_INET, &((struct sockaddr_in*)result->ai_addr)->sin_addr, buf, sizeof(buf)); break; case AF_INET6: inet_ntop(AF_INET6, &((struct sockaddr_in6*)result->ai_addr)->sin6_addr, buf, sizeof(buf)); break; default: return nil; } } else return nil; return strdup(buf); } int so_getservbyname(char *service, char *net, char *port) { struct servent *s; s = getservbyname(service, net); if(s == 0) return -1; sprint(port, "%d", nhgets(&s->s_port)); return 0; } int so_send(int fd, void *d, int n, int f) { return send(fd, d, n, f); } int so_recv(int fd, void *d, int n, int f) { return recv(fd, d, n, f); } drawterm-20170818/kern/devip-win32.c000066400000000000000000000117101314554504700167750ustar00rootroot00000000000000#include #include #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "ip.h" #include "devip.h" #ifdef MSVC #pragma comment(lib, "wsock32.lib") #endif #undef listen #undef accept #undef bind static int family(unsigned char *addr) { if(isv4(addr)) return AF_INET; return AF_INET6; } static int addrlen(struct sockaddr_storage *ss) { switch(ss->ss_family){ case AF_INET: return sizeof(struct sockaddr_in); case AF_INET6: return sizeof(struct sockaddr_in6); } return 0; } void osipinit(void) { WSADATA wasdat; char buf[1024]; if(WSAStartup(MAKEWORD(1, 1), &wasdat) != 0) panic("no winsock.dll"); gethostname(buf, sizeof(buf)); kstrdup(&sysname, buf); } int so_socket(int type, unsigned char *addr) { int fd, one; switch(type) { default: error("bad protocol type"); case S_TCP: type = SOCK_STREAM; break; case S_UDP: type = SOCK_DGRAM; break; } fd = socket(family(addr), type, 0); if(fd < 0) oserror(); one = 1; if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0){ oserrstr(); print("setsockopt: %s\n", up->errstr); } return fd; } void so_connect(int fd, unsigned char *raddr, unsigned short rport) { struct sockaddr_storage ss; memset(&ss, 0, sizeof(ss)); ss.ss_family = family(raddr); switch(ss.ss_family){ case AF_INET: hnputs(&((struct sockaddr_in*)&ss)->sin_port, rport); v6tov4((unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr, raddr); break; case AF_INET6: hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, rport); memcpy(&((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, raddr, sizeof(struct in6_addr)); break; } if(connect(fd, (struct sockaddr*)&ss, addrlen(&ss)) < 0) oserror(); } void so_getsockname(int fd, unsigned char *laddr, unsigned short *lport) { int len; struct sockaddr_storage ss; len = sizeof(ss); if(getsockname(fd, (struct sockaddr*)&ss, &len) < 0) oserror(); switch(ss.ss_family){ case AF_INET: v4tov6(laddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr); *lport = nhgets(&((struct sockaddr_in*)&ss)->sin_port); break; case AF_INET6: memcpy(laddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr)); *lport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port); break; default: error("not AF_INET or AF_INET6"); } } void so_listen(int fd) { if(listen(fd, 5) < 0) oserror(); } int so_accept(int fd, unsigned char *raddr, unsigned short *rport) { int nfd; int len; struct sockaddr_storage ss; len = sizeof(ss); nfd = accept(fd, (struct sockaddr*)&ss, &len); if(nfd < 0) oserror(); switch(ss.ss_family){ case AF_INET: v4tov6(raddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr); *rport = nhgets(&((struct sockaddr_in*)&ss)->sin_port); break; case AF_INET6: memcpy(raddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr)); *rport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port); break; default: error("not AF_INET or AF_INET6"); } return nfd; } void so_bind(int fd, int su, unsigned short port, unsigned char *addr) { int i, one; struct sockaddr_storage ss; one = 1; if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0){ oserrstr(); print("setsockopt: %r"); } if(su) { for(i = 600; i < 1024; i++) { memset(&ss, 0, sizeof(ss)); ss.ss_family = family(addr); switch(ss.ss_family){ case AF_INET: ((struct sockaddr_in*)&ss)->sin_port = i; break; case AF_INET6: ((struct sockaddr_in6*)&ss)->sin6_port = i; break; } if(bind(fd, (struct sockaddr*)&ss, addrlen(&ss)) >= 0) return; } oserror(); } memset(&ss, 0, sizeof(ss)); ss.ss_family = family(addr); switch(ss.ss_family){ case AF_INET: hnputs(&((struct sockaddr_in*)&ss)->sin_port, port); break; case AF_INET6: hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, port); break; } if(bind(fd, (struct sockaddr*)&ss, addrlen(&ss)) < 0) oserror(); } int so_gethostbyname(char *host, char**hostv, int n) { int i; char buf[32]; unsigned char *p; struct hostent *hp; hp = gethostbyname(host); if(hp == 0) return 0; for(i = 0; hp->h_addr_list[i] && i < n; i++) { p = (unsigned char*)hp->h_addr_list[i]; sprint(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); hostv[i] = strdup(buf); if(hostv[i] == 0) break; } return i; } char* hostlookup(char *host) { char buf[100]; uchar *p; struct hostent *he; he = gethostbyname(host); if(he != 0 && he->h_addr_list[0]) { p = (uchar*)he->h_addr_list[0]; sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]); } else strcpy(buf, host); return strdup(buf); } int so_getservbyname(char *service, char *net, char *port) { struct servent *s; s = getservbyname(service, net); if(s == 0) return -1; sprint(port, "%d", nhgets(&s->s_port)); return 0; } int so_send(int fd, void *d, int n, int f) { return send(fd, d, n, f); } int so_recv(int fd, void *d, int n, int f) { return recv(fd, d, n, f); } drawterm-20170818/kern/devip.c000066400000000000000000000320501314554504700160350ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "ip.h" #include "devip.h" void csclose(Chan*); long csread(Chan*, void*, long, vlong); long cswrite(Chan*, void*, long, vlong); void osipinit(void); enum { Qtopdir = 1, /* top level directory */ Qcs, Qprotodir, /* directory for a protocol */ Qclonus, Qconvdir, /* directory for a conversation */ Qdata, Qctl, Qstatus, Qremote, Qlocal, Qlisten, MAXPROTO = 4 }; #define TYPE(x) ((int)((x).path & 0xf)) #define CONV(x) ((int)(((x).path >> 4)&0xfff)) #define PROTO(x) ((int)(((x).path >> 16)&0xff)) #define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y)) #define ipzero(x) memset(x, 0, IPaddrlen) typedef struct Proto Proto; typedef struct Conv Conv; struct Conv { int x; Ref r; int sfd; int perm; char owner[KNAMELEN]; char* state; uchar laddr[IPaddrlen]; ushort lport; uchar raddr[IPaddrlen]; ushort rport; int restricted; char cerr[KNAMELEN]; Proto* p; }; struct Proto { Lock l; int x; int stype; char name[KNAMELEN]; int nc; int maxconv; Conv** conv; Qid qid; }; static int np; static Proto proto[MAXPROTO]; static Conv* protoclone(Proto*, char*, int); static void setladdr(Conv*); int ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp) { Qid q; Conv *cv; char *p; USED(nname); q.vers = 0; q.type = 0; switch(TYPE(c->qid)) { case Qtopdir: if(s >= 1+np) return -1; if(s == 0){ q.path = QID(s, 0, Qcs); devdir(c, q, "cs", 0, "network", 0666, dp); }else{ s--; q.path = QID(s, 0, Qprotodir); q.type = QTDIR; devdir(c, q, proto[s].name, 0, "network", DMDIR|0555, dp); } return 1; case Qprotodir: if(s < proto[PROTO(c->qid)].nc) { cv = proto[PROTO(c->qid)].conv[s]; sprint(up->genbuf, "%d", s); q.path = QID(PROTO(c->qid), s, Qconvdir); q.type = QTDIR; devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp); return 1; } s -= proto[PROTO(c->qid)].nc; switch(s) { default: return -1; case 0: p = "clone"; q.path = QID(PROTO(c->qid), 0, Qclonus); break; } devdir(c, q, p, 0, "network", 0555, dp); return 1; case Qconvdir: cv = proto[PROTO(c->qid)].conv[CONV(c->qid)]; switch(s) { default: return -1; case 0: q.path = QID(PROTO(c->qid), CONV(c->qid), Qdata); devdir(c, q, "data", 0, cv->owner, cv->perm, dp); return 1; case 1: q.path = QID(PROTO(c->qid), CONV(c->qid), Qctl); devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); return 1; case 2: p = "status"; q.path = QID(PROTO(c->qid), CONV(c->qid), Qstatus); break; case 3: p = "remote"; q.path = QID(PROTO(c->qid), CONV(c->qid), Qremote); break; case 4: p = "local"; q.path = QID(PROTO(c->qid), CONV(c->qid), Qlocal); break; case 5: p = "listen"; q.path = QID(PROTO(c->qid), CONV(c->qid), Qlisten); break; } devdir(c, q, p, 0, cv->owner, 0444, dp); return 1; } return -1; } static void newproto(char *name, int type, int maxconv) { int l; Proto *p; if(np >= MAXPROTO) { print("no %s: increase MAXPROTO", name); return; } p = &proto[np]; strcpy(p->name, name); p->stype = type; p->qid.path = QID(np, 0, Qprotodir); p->qid.type = QTDIR; p->x = np++; p->maxconv = maxconv; l = sizeof(Conv*)*(p->maxconv+1); p->conv = mallocz(l, 1); if(p->conv == 0) panic("no memory"); } void ipinit(void) { osipinit(); newproto("udp", S_UDP, 10); newproto("tcp", S_TCP, 30); fmtinstall('I', eipfmt); fmtinstall('E', eipfmt); } Chan * ipattach(char *spec) { Chan *c; c = devattach('I', spec); c->qid.path = QID(0, 0, Qtopdir); c->qid.type = QTDIR; c->qid.vers = 0; return c; } static Walkqid* ipwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, 0, 0, ipgen); } int ipstat(Chan *c, uchar *dp, int n) { return devstat(c, dp, n, 0, 0, ipgen); } Chan * ipopen(Chan *c, int omode) { Proto *p; uchar raddr[IPaddrlen]; ushort rport; int perm, sfd; Conv *cv, *lcv; omode &= 3; perm = 0; switch(omode) { case OREAD: perm = 4; break; case OWRITE: perm = 2; break; case ORDWR: perm = 6; break; } switch(TYPE(c->qid)) { default: break; case Qtopdir: case Qprotodir: case Qconvdir: case Qstatus: case Qremote: case Qlocal: if(omode != OREAD) error(Eperm); break; case Qclonus: p = &proto[PROTO(c->qid)]; cv = protoclone(p, up->user, -1); if(cv == 0) error(Enodev); c->qid.path = QID(p->x, cv->x, Qctl); c->qid.vers = 0; break; case Qdata: case Qctl: p = &proto[PROTO(c->qid)]; lock(&p->l); cv = p->conv[CONV(c->qid)]; lock(&cv->r.lk); if((perm & (cv->perm>>6)) != perm) { if(strcmp(up->user, cv->owner) != 0 || (perm & cv->perm) != perm) { unlock(&cv->r.lk); unlock(&p->l); error(Eperm); } } cv->r.ref++; if(cv->r.ref == 1) { memmove(cv->owner, up->user, KNAMELEN); cv->perm = 0660; } unlock(&cv->r.lk); unlock(&p->l); break; case Qlisten: p = &proto[PROTO(c->qid)]; lcv = p->conv[CONV(c->qid)]; sfd = so_accept(lcv->sfd, raddr, &rport); cv = protoclone(p, up->user, sfd); if(cv == 0) { close(sfd); error(Enodev); } ipmove(cv->raddr, raddr); cv->rport = rport; setladdr(cv); cv->state = "Established"; c->qid.path = QID(p->x, cv->x, Qctl); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } void ipclose(Chan *c) { Conv *cc; switch(TYPE(c->qid)) { case Qcs: csclose(c); break; case Qdata: case Qctl: if((c->flag & COPEN) == 0) break; cc = proto[PROTO(c->qid)].conv[CONV(c->qid)]; if(decref(&cc->r) != 0) break; strcpy(cc->owner, "network"); cc->perm = 0666; cc->state = "Closed"; ipzero(cc->laddr); ipzero(cc->raddr); cc->lport = 0; cc->rport = 0; close(cc->sfd); break; } } long ipread(Chan *ch, void *a, long n, vlong offset) { int r; Conv *c; Proto *x; uchar ip[IPaddrlen]; char buf[128], *p; /*print("ipread %s %lux\n", c2name(ch), (long)ch->qid.path);*/ p = a; switch(TYPE(ch->qid)) { default: error(Eperm); case Qcs: return csread(ch, a, n, offset); case Qprotodir: case Qtopdir: case Qconvdir: return devdirread(ch, a, n, 0, 0, ipgen); case Qctl: sprint(buf, "%d", CONV(ch->qid)); return readstr(offset, p, n, buf); case Qremote: c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; ipmove(ip, c->raddr); sprint(buf, "%I!%d\n", ip, c->rport); return readstr(offset, p, n, buf); case Qlocal: c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; ipmove(ip, c->laddr); sprint(buf, "%I!%d\n", ip, c->lport); return readstr(offset, p, n, buf); case Qstatus: x = &proto[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; sprint(buf, "%s/%d %d %s \n", c->p->name, c->x, c->r.ref, c->state); return readstr(offset, p, n, buf); case Qdata: c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; r = so_recv(c->sfd, a, n, 0); if(r < 0){ oserrstr(); nexterror(); } return r; } } static void setladdr(Conv *c) { so_getsockname(c->sfd, c->laddr, &c->lport); } static void setlport(Conv *c) { if(c->restricted == 0 && c->lport == 0) return; if(c->sfd == -1) c->sfd = so_socket(c->p->stype, c->laddr); so_bind(c->sfd, c->restricted, c->lport, c->laddr); } static void setladdrport(Conv *c, char *str) { char *p; uchar addr[IPaddrlen]; p = strchr(str, '!'); if(p == 0) { p = str; ipzero(c->laddr); } else { *p++ = 0; parseip(addr, str); ipmove(c->laddr, addr); } if(*p == '*') c->lport = 0; else c->lport = atoi(p); setlport(c); } static char* setraddrport(Conv *c, char *str) { char *p; uchar addr[IPaddrlen]; p = strchr(str, '!'); if(p == 0) return "malformed address"; *p++ = 0; parseip(addr, str); ipmove(c->raddr, addr); c->rport = atoi(p); p = strchr(p, '!'); if(p) { if(strcmp(p, "!r") == 0) c->restricted = 1; } return 0; } long ipwrite(Chan *ch, void *a, long n, vlong offset) { Conv *c; Proto *x; int r, nf; char *p, *fields[3], buf[128]; switch(TYPE(ch->qid)) { default: error(Eperm); case Qcs: return cswrite(ch, a, n, offset); case Qctl: x = &proto[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; if(n > sizeof(buf)-1) n = sizeof(buf)-1; memmove(buf, a, n); buf[n] = '\0'; nf = tokenize(buf, fields, 3); if(strcmp(fields[0], "connect") == 0){ switch(nf) { default: error("bad args to connect"); case 2: p = setraddrport(c, fields[1]); if(p != 0) error(p); break; case 3: p = setraddrport(c, fields[1]); if(p != 0) error(p); c->lport = atoi(fields[2]); setlport(c); break; } if(c->sfd == -1) c->sfd = so_socket(c->p->stype, c->raddr); so_connect(c->sfd, c->raddr, c->rport); setladdr(c); c->state = "Established"; return n; } if(strcmp(fields[0], "announce") == 0) { switch(nf){ default: error("bad args to announce"); case 2: setladdrport(c, fields[1]); break; } so_listen(c->sfd); c->state = "Announced"; return n; } if(strcmp(fields[0], "bind") == 0){ switch(nf){ default: error("bad args to bind"); case 2: c->lport = atoi(fields[1]); break; } setlport(c); return n; } error("bad control message"); case Qdata: x = &proto[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; r = so_send(c->sfd, a, n, 0); if(r < 0){ oserrstr(); nexterror(); } return r; } return n; } static Conv* protoclone(Proto *p, char *user, int nfd) { Conv *c, **pp, **ep; c = 0; lock(&p->l); if(waserror()) { unlock(&p->l); nexterror(); } ep = &p->conv[p->maxconv]; for(pp = p->conv; pp < ep; pp++) { c = *pp; if(c == 0) { c = mallocz(sizeof(Conv), 1); if(c == 0) error(Enomem); lock(&c->r.lk); c->r.ref = 1; c->p = p; c->x = pp - p->conv; p->nc++; *pp = c; break; } lock(&c->r.lk); if(c->r.ref == 0) { c->r.ref++; break; } unlock(&c->r.lk); } if(pp >= ep) { unlock(&p->l); poperror(); return 0; } strcpy(c->owner, user); c->perm = 0660; c->state = "Closed"; c->restricted = 0; ipzero(c->laddr); ipzero(c->raddr); c->lport = 0; c->rport = 0; c->sfd = nfd; unlock(&c->r.lk); unlock(&p->l); poperror(); return c; } void csclose(Chan *c) { free(c->aux); } long csread(Chan *c, void *a, long n, vlong offset) { if(c->aux == nil) return 0; return readstr(offset, a, n, c->aux); } static struct { char *name; uint num; } tab[] = { "cs", 1, "echo", 7, "discard", 9, "systat", 11, "daytime", 13, "netstat", 15, "chargen", 19, "ftp-data", 20, "ftp", 21, "ssh", 22, "telnet", 23, "smtp", 25, "time", 37, "whois", 43, "dns", 53, "domain", 53, "uucp", 64, "gopher", 70, "rje", 77, "finger", 79, "http", 80, "link", 87, "supdup", 95, "hostnames", 101, "iso-tsap", 102, "x400", 103, "x400-snd", 104, "csnet-ns", 105, "pop-2", 109, "pop3", 110, "portmap", 111, "uucp-path", 117, "nntp", 119, "netbios", 139, "imap4", 143, "NeWS", 144, "print-srv", 170, "z39.50", 210, "fsb", 400, "sysmon", 401, "proxy", 402, "proxyd", 404, "https", 443, "cifs", 445, "ssmtp", 465, "rexec", 512, "login", 513, "shell", 514, "printer", 515, "courier", 530, "cscan", 531, "uucp", 540, "snntp", 563, "9fs", 564, "whoami", 565, "guard", 566, "ticket", 567, "dlsftp", 666, "fmclient", 729, "imaps", 993, "pop3s", 995, "ingreslock", 1524, "pptp", 1723, "nfs", 2049, "webster", 2627, "weather", 3000, "secstore", 5356, "Xdisplay", 6000, "styx", 6666, "mpeg", 6667, "rstyx", 6668, "infdb", 6669, "infsigner", 6671, "infcsigner", 6672, "inflogin", 6673, "bandt", 7330, "face", 32000, "dhashgate", 11978, "exportfs", 17007, "rexexec", 17009, "ncpu", 17010, "cpu", 17013, "glenglenda1", 17020, "glenglenda2", 17021, "glenglenda3", 17022, "glenglenda4", 17023, "glenglenda5", 17024, "glenglenda6", 17025, "glenglenda7", 17026, "glenglenda8", 17027, "glenglenda9", 17028, "glenglenda10", 17029, "flyboy", 17032, "dlsftp", 17033, "venti", 17034, "wiki", 17035, "vica", 17036, 0 }; static int lookupport(char *s) { int i; char buf[10], *p; i = strtol(s, &p, 0); if(*s && *p == 0) return i; i = so_getservbyname(s, "tcp", buf); if(i != -1) return atoi(buf); for(i=0; tab[i].name; i++) if(strcmp(s, tab[i].name) == 0) return tab[i].num; return 0; } static int lookuphost(char *s, uchar *to) { ipzero(to); if(parseip(to, s) != -1) return 0; if((s = hostlookup(s)) == nil) return -1; parseip(to, s); free(s); return 0; } long cswrite(Chan *c, void *a, long n, vlong offset) { char *f[4]; char *s, *ns; uchar ip[IPaddrlen]; int nf, port; s = malloc(n+1); if(s == nil) error(Enomem); if(waserror()){ free(s); nexterror(); } memmove(s, a, n); s[n] = 0; nf = getfields(s, f, nelem(f), 0, "!"); if(nf != 3) error("can't translate"); port = lookupport(f[2]); if(port <= 0) error("no translation for port found"); if(lookuphost(f[1], ip) < 0) error("no translation for host found"); ns = smprint("/net/%s/clone %I!%d", f[0], ip, port); if(ns == nil) error(Enomem); free(c->aux); c->aux = ns; poperror(); free(s); return n; } Dev ipdevtab = { 'I', "ip", devreset, ipinit, devshutdown, ipattach, ipwalk, ipstat, ipopen, devcreate, ipclose, ipread, devbread, ipwrite, devbwrite, devremove, devwstat, }; drawterm-20170818/kern/devip.h000066400000000000000000000007611314554504700160460ustar00rootroot00000000000000enum { S_TCP, S_UDP }; int so_socket(int, unsigned char*); void so_connect(int, unsigned char*, unsigned short); void so_getsockname(int, unsigned char*, unsigned short*); void so_bind(int, int, unsigned short, unsigned char*); void so_listen(int); int so_send(int, void*, int, int); int so_recv(int, void*, int, int); int so_accept(int, unsigned char*, unsigned short*); int so_getservbyname(char*, char*, char*); int so_gethostbyname(char*, char**, int); char* hostlookup(char*); drawterm-20170818/kern/devlfd.c000066400000000000000000000030421314554504700161710ustar00rootroot00000000000000#include "u.h" #include #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #undef pread #undef pwrite Chan* lfdchan(int fd) { Chan *c; c = newchan(); c->type = devno('L', 0); c->aux = (void*)(uintptr)fd; c->name = newcname("fd"); c->mode = ORDWR; c->qid.type = 0; c->qid.path = 0; c->qid.vers = 0; c->dev = 0; c->offset = 0; return c; } int lfdfd(int fd) { return newfd(lfdchan(fd)); } static Chan* lfdattach(char *x) { USED(x); error(Egreg); return nil; } static Walkqid* lfdwalk(Chan *c, Chan *nc, char **name, int nname) { USED(c); USED(nc); USED(name); USED(nname); error(Egreg); return nil; } static int lfdstat(Chan *c, uchar *dp, int n) { USED(c); USED(dp); USED(n); error(Egreg); return -1; } static Chan* lfdopen(Chan *c, int omode) { USED(c); USED(omode); error(Egreg); return nil; } static void lfdclose(Chan *c) { close((int)(uintptr)c->aux); } static long lfdread(Chan *c, void *buf, long n, vlong off) { USED(off); /* can't pread on pipes */ n = read((int)(uintptr)c->aux, buf, n); if(n < 0){ iprint("error %d\n", errno); oserror(); } return n; } static long lfdwrite(Chan *c, void *buf, long n, vlong off) { USED(off); /* can't pread on pipes */ n = write((int)(uintptr)c->aux, buf, n); if(n < 0){ iprint("error %d\n", errno); oserror(); } return n; } Dev lfddevtab = { 'L', "lfd", devreset, devinit, devshutdown, lfdattach, lfdwalk, lfdstat, lfdopen, devcreate, lfdclose, lfdread, devbread, lfdwrite, devbwrite, devremove, devwstat, }; drawterm-20170818/kern/devmnt.c000066400000000000000000000523251314554504700162320ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" /* * References are managed as follows: * The channel to the server - a network connection or pipe - has one * reference for every Chan open on the server. The server channel has * c->mux set to the Mnt used for muxing control to that server. Mnts * have no reference count; they go away when c goes away. * Each channel derived from the mount point has mchan set to c, * and increfs/decrefs mchan to manage references on the server * connection. */ #define MAXRPC (IOHDRSZ+8192) struct Mntrpc { Chan* c; /* Channel for whom we are working */ Mntrpc* list; /* Free/pending list */ Fcall request; /* Outgoing file system protocol message */ Fcall reply; /* Incoming reply */ Mnt* m; /* Mount device during rpc */ Rendez r; /* Place to hang out */ uchar* rpc; /* I/O Data buffer */ uint rpclen; /* len of buffer */ Block *b; /* reply blocks */ char done; /* Rpc completed */ uvlong stime; /* start time for mnt statistics */ ulong reqlen; /* request length for mnt statistics */ ulong replen; /* reply length for mnt statistics */ Mntrpc* flushed; /* message this one flushes */ }; enum { TAGSHIFT = 5, /* ulong has to be 32 bits */ TAGMASK = (1<>TAGSHIFT, }; struct Mntalloc { Lock lk; Mnt* list; /* Mount devices in use */ Mnt* mntfree; /* Free list */ Mntrpc* rpcfree; int nrpcfree; int nrpcused; ulong id; ulong tagmask[NMASK]; }mntalloc; void mattach(Mnt*, Chan*, char*); Mnt* mntchk(Chan*); void mntdirfix(uchar*, Chan*); Mntrpc* mntflushalloc(Mntrpc*, ulong); void mntflushfree(Mnt*, Mntrpc*); void mntfree(Mntrpc*); void mntgate(Mnt*); void mntpntfree(Mnt*); void mntqrm(Mnt*, Mntrpc*); Mntrpc* mntralloc(Chan*, ulong); long mntrdwr(int, Chan*, void*, long, vlong); int mntrpcread(Mnt*, Mntrpc*); void mountio(Mnt*, Mntrpc*); void mountmux(Mnt*, Mntrpc*); void mountrpc(Mnt*, Mntrpc*); int rpcattn(void*); Chan* mntchan(void); char Esbadstat[] = "invalid directory entry received from server"; char Enoversion[] = "version not established for mount channel"; void (*mntstats)(int, Chan*, uvlong, ulong); static void mntreset(void) { mntalloc.id = 1; mntalloc.tagmask[0] = 1; /* don't allow 0 as a tag */ mntalloc.tagmask[NMASK-1] = 0x80000000UL; /* don't allow NOTAG */ fmtinstall('F', fcallfmt); fmtinstall('D', dirfmt); /* We can't install %M since eipfmt does and is used in the kernel [sape] */ cinit(); } /* * Version is not multiplexed: message sent only once per connection. */ long mntversion(Chan *c, char *version, int msize, int returnlen) { Fcall f; uchar *msg; Mnt *m; char *v; long k, l; uvlong oo; char buf[128]; qlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */ if(waserror()){ qunlock(&c->umqlock); nexterror(); } /* defaults */ if(msize == 0) msize = MAXRPC; if(msize > c->iounit && c->iounit != 0) msize = c->iounit; v = version; if(v == nil || v[0] == '\0') v = VERSION9P; /* validity */ if(msize < 0) error("bad iounit in version call"); if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0) error("bad 9P version specification"); m = c->mux; if(m != nil){ qunlock(&c->umqlock); poperror(); strecpy(buf, buf+sizeof buf, m->version); k = strlen(buf); if(strncmp(buf, v, k) != 0){ snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v); error(buf); } if(returnlen > 0){ if(returnlen < k) error(Eshort); memmove(version, buf, k); } return k; } f.type = Tversion; f.tag = NOTAG; f.msize = msize; f.version = v; msg = malloc(8192+IOHDRSZ); if(msg == nil) exhausted("version memory"); if(waserror()){ free(msg); nexterror(); } k = convS2M(&f, msg, 8192+IOHDRSZ); if(k == 0) error("bad fversion conversion on send"); lock(&c->ref.lk); oo = c->offset; c->offset += k; unlock(&c->ref.lk); l = devtab[c->type]->write(c, msg, k, oo); if(l < k){ lock(&c->ref.lk); c->offset -= k - l; unlock(&c->ref.lk); error("short write in fversion"); } /* message sent; receive and decode reply */ k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset); if(k <= 0) error("EOF receiving fversion reply"); lock(&c->ref.lk); c->offset += k; unlock(&c->ref.lk); l = convM2S(msg, k, &f); if(l != k) error("bad fversion conversion on reply"); if(f.type != Rversion){ if(f.type == Rerror) error(f.ename); error("unexpected reply type in fversion"); } if(f.msize > msize) error("server tries to increase msize in fversion"); if(f.msize<256 || f.msize>1024*1024) error("nonsense value of msize in fversion"); k = strlen(f.version); if(strncmp(f.version, v, k) != 0) error("bad 9P version returned from server"); /* now build Mnt associated with this connection */ lock(&mntalloc.lk); m = mntalloc.mntfree; if(m != 0) mntalloc.mntfree = m->list; else { m = malloc(sizeof(Mnt)); if(m == 0) { unlock(&mntalloc.lk); exhausted("mount devices"); } } m->list = mntalloc.list; mntalloc.list = m; m->version = nil; kstrdup(&m->version, f.version); m->id = mntalloc.id++; m->q = qopen(10*MAXRPC, 0, 0, nil); m->msize = f.msize; unlock(&mntalloc.lk); if(returnlen > 0){ if(returnlen < k) error(Eshort); memmove(version, f.version, k); } poperror(); /* msg */ free(msg); lock(&m->lk); m->queue = 0; m->rip = 0; c->flag |= CMSG; c->mux = m; m->c = c; unlock(&m->lk); poperror(); /* c */ qunlock(&c->umqlock); return k; } Chan* mntauth(Chan *c, char *spec) { Mnt *m; Mntrpc *r; m = c->mux; if(m == nil){ mntversion(c, VERSION9P, MAXRPC, 0); m = c->mux; if(m == nil) error(Enoversion); } c = mntchan(); if(waserror()) { /* Close must not be called since it will * call mnt recursively */ chanfree(c); nexterror(); } r = mntralloc(0, m->msize); if(waserror()) { mntfree(r); nexterror(); } r->request.type = Tauth; r->request.afid = c->fid; r->request.uname = up->user; r->request.aname = spec; mountrpc(m, r); c->qid = r->reply.aqid; c->mchan = m->c; incref(&m->c->ref); c->mqid = c->qid; c->mode = ORDWR; poperror(); /* r */ mntfree(r); poperror(); /* c */ return c; } static Chan* mntattach(char *muxattach) { Mnt *m; Chan *c; Mntrpc *r; struct bogus{ Chan *chan; Chan *authchan; char *spec; int flags; }bogus; bogus = *((struct bogus *)muxattach); c = bogus.chan; m = c->mux; if(m == nil){ mntversion(c, nil, 0, 0); m = c->mux; if(m == nil) error(Enoversion); } c = mntchan(); if(waserror()) { /* Close must not be called since it will * call mnt recursively */ chanfree(c); nexterror(); } r = mntralloc(0, m->msize); if(waserror()) { mntfree(r); nexterror(); } r->request.type = Tattach; r->request.fid = c->fid; if(bogus.authchan == nil) r->request.afid = NOFID; else r->request.afid = bogus.authchan->fid; r->request.uname = up->user; r->request.aname = bogus.spec; mountrpc(m, r); c->qid = r->reply.qid; c->mchan = m->c; incref(&m->c->ref); c->mqid = c->qid; poperror(); /* r */ mntfree(r); poperror(); /* c */ if(bogus.flags&MCACHE) c->flag |= CCACHE; return c; } Chan* mntchan(void) { Chan *c; c = devattach('M', 0); lock(&mntalloc.lk); c->dev = mntalloc.id++; unlock(&mntalloc.lk); if(c->mchan) panic("mntchan non-zero %p", c->mchan); return c; } static Walkqid* mntwalk(Chan *c, Chan *nc, char **name, int nname) { int i, alloc; Mnt *m; Mntrpc *r; Walkqid *wq; if(nc != nil) print("mntwalk: nc != nil\n"); if(nname > MAXWELEM) error("devmnt: too many name elements"); alloc = 0; wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); if(waserror()){ if(alloc && wq->clone!=nil) cclose(wq->clone); free(wq); return nil; } alloc = 0; m = mntchk(c); r = mntralloc(c, m->msize); if(nc == nil){ nc = devclone(c); /* * Until the other side accepts this fid, we can't mntclose it. * Therefore set type to 0 for now; rootclose is known to be safe. */ nc->type = 0; alloc = 1; } wq->clone = nc; if(waserror()) { mntfree(r); nexterror(); } r->request.type = Twalk; r->request.fid = c->fid; r->request.newfid = nc->fid; r->request.nwname = nname; memmove(r->request.wname, name, nname*sizeof(char*)); mountrpc(m, r); if(r->reply.nwqid > nname) error("too many QIDs returned by walk"); if(r->reply.nwqid < nname){ if(alloc) cclose(nc); wq->clone = nil; if(r->reply.nwqid == 0){ free(wq); wq = nil; goto Return; } } /* move new fid onto mnt device and update its qid */ if(wq->clone != nil){ if(wq->clone != c){ wq->clone->type = c->type; wq->clone->mchan = c->mchan; incref(&c->mchan->ref); } if(r->reply.nwqid > 0) wq->clone->qid = r->reply.wqid[r->reply.nwqid-1]; } wq->nqid = r->reply.nwqid; for(i=0; inqid; i++) wq->qid[i] = r->reply.wqid[i]; Return: poperror(); mntfree(r); poperror(); return wq; } static int mntstat(Chan *c, uchar *dp, int n) { Mnt *m; Mntrpc *r; if(n < BIT16SZ) error(Eshortstat); m = mntchk(c); r = mntralloc(c, m->msize); if(waserror()) { mntfree(r); nexterror(); } r->request.type = Tstat; r->request.fid = c->fid; mountrpc(m, r); /* r->reply.nstat is 16 bits if(r->reply.nstat >= 1<<16) error("returned stat buffer count too large"); */ if(r->reply.nstat > n){ /* * 12/31/2002 RSC * * This should be nstat-2, which is the first two * bytes of the stat buffer. But dirstat and dirfstat * depended on getting the full nstat (they didn't * add BIT16SZ themselves). I fixed dirstat and dirfstat * but am leaving this unchanged for now. After a * few months, once enough of the relevant binaries * have been recompiled for other reasons, we can * change this to nstat-2. Devstat gets this right * (via convD2M). */ /* doesn't fit; just patch the count and return */ PBIT16((uchar*)dp, r->reply.nstat); n = BIT16SZ; }else{ n = r->reply.nstat; memmove(dp, r->reply.stat, n); validstat(dp, n); mntdirfix(dp, c); } poperror(); mntfree(r); return n; } static Chan* mntopencreate(int type, Chan *c, char *name, int omode, ulong perm) { Mnt *m; Mntrpc *r; m = mntchk(c); r = mntralloc(c, m->msize); if(waserror()) { mntfree(r); nexterror(); } r->request.type = type; r->request.fid = c->fid; r->request.mode = omode; if(type == Tcreate){ r->request.perm = perm; r->request.name = name; } mountrpc(m, r); c->qid = r->reply.qid; c->offset = 0; c->mode = openmode(omode); c->iounit = r->reply.iounit; if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ) c->iounit = m->msize-IOHDRSZ; c->flag |= COPEN; poperror(); mntfree(r); if(c->flag & CCACHE) copen(c); return c; } static Chan* mntopen(Chan *c, int omode) { return mntopencreate(Topen, c, nil, omode, 0); } static void mntcreate(Chan *c, char *name, int omode, ulong perm) { mntopencreate(Tcreate, c, name, omode, perm); } static void mntclunk(Chan *c, int t) { Mnt *m; Mntrpc *r; m = mntchk(c); r = mntralloc(c, m->msize); if(waserror()){ mntfree(r); nexterror(); } r->request.type = t; r->request.fid = c->fid; mountrpc(m, r); mntfree(r); poperror(); } void muxclose(Mnt *m) { Mntrpc *q, *r; for(q = m->queue; q; q = r) { r = q->list; mntfree(q); } m->id = 0; free(m->version); m->version = nil; mntpntfree(m); } void mntpntfree(Mnt *m) { Mnt *f, **l; Queue *q; lock(&mntalloc.lk); l = &mntalloc.list; for(f = *l; f; f = f->list) { if(f == m) { *l = m->list; break; } l = &f->list; } m->list = mntalloc.mntfree; mntalloc.mntfree = m; q = m->q; unlock(&mntalloc.lk); qfree(q); } static void mntclose(Chan *c) { mntclunk(c, Tclunk); } static void mntremove(Chan *c) { mntclunk(c, Tremove); } static int mntwstat(Chan *c, uchar *dp, int n) { Mnt *m; Mntrpc *r; m = mntchk(c); r = mntralloc(c, m->msize); if(waserror()) { mntfree(r); nexterror(); } r->request.type = Twstat; r->request.fid = c->fid; r->request.nstat = n; r->request.stat = dp; mountrpc(m, r); poperror(); mntfree(r); return n; } static long mntread(Chan *c, void *buf, long n, vlong off) { uchar *p, *e; int nc, cache, isdir, dirlen; isdir = 0; cache = c->flag & CCACHE; if(c->qid.type & QTDIR) { cache = 0; isdir = 1; } p = buf; if(cache) { nc = cread(c, buf, n, off); if(nc > 0) { n -= nc; if(n == 0) return nc; p += nc; off += nc; } n = mntrdwr(Tread, c, p, n, off); cupdate(c, p, n, off); return n + nc; } n = mntrdwr(Tread, c, buf, n, off); if(isdir) { for(e = &p[n]; p+BIT16SZ < e; p += dirlen){ dirlen = BIT16SZ+GBIT16(p); if(p+dirlen > e) break; validstat(p, dirlen); mntdirfix(p, c); } if(p != e) error(Esbadstat); } return n; } static long mntwrite(Chan *c, void *buf, long n, vlong off) { return mntrdwr(Twrite, c, buf, n, off); } long mntrdwr(int type, Chan *c, void *buf, long n, vlong off) { Mnt *m; Mntrpc *r; char *uba; int cache; ulong cnt, nr, nreq; m = mntchk(c); uba = buf; cnt = 0; cache = c->flag & CCACHE; if(c->qid.type & QTDIR) cache = 0; for(;;) { r = mntralloc(c, m->msize); if(waserror()) { mntfree(r); nexterror(); } r->request.type = type; r->request.fid = c->fid; r->request.offset = off; r->request.data = uba; nr = n; if(nr > m->msize-IOHDRSZ) nr = m->msize-IOHDRSZ; r->request.count = nr; mountrpc(m, r); nreq = r->request.count; nr = r->reply.count; if(nr > nreq) nr = nreq; if(type == Tread) r->b = bl2mem((uchar*)uba, r->b, nr); else if(cache) cwrite(c, (uchar*)uba, nr, off); poperror(); mntfree(r); off += nr; uba += nr; cnt += nr; n -= nr; if(nr != nreq || n == 0) break; } return cnt; } void mountrpc(Mnt *m, Mntrpc *r) { char *sn, *cn; int t; r->reply.tag = 0; r->reply.type = Tmax; /* can't ever be a valid message type */ mountio(m, r); t = r->reply.type; switch(t) { case Rerror: error(r->reply.ename); case Rflush: error(Eintr); default: if(t == r->request.type+1) break; sn = "?"; if(m->c->name != nil) sn = m->c->name->s; cn = "?"; if(r->c != nil && r->c->name != nil) cn = r->c->name->s; print("mnt: proc %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n", up->pid, sn, cn, r, r->request.tag, r->request.fid, r->request.type, r->reply.type, r->reply.tag); error(Emountrpc); } } void mountio(Mnt *m, Mntrpc *r) { int n; while(waserror()) { if(m->rip == up) mntgate(m); if(strcmp(up->errstr, Eintr) != 0){ mntflushfree(m, r); nexterror(); } r = mntflushalloc(r, m->msize); } lock(&m->lk); r->m = m; r->list = m->queue; m->queue = r; unlock(&m->lk); /* Transmit a file system rpc */ if(m->msize == 0) panic("msize"); n = convS2M(&r->request, r->rpc, m->msize); if(n < 0) panic("bad message type in mountio"); if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n) error(Emountrpc); r->stime = fastticks(nil); r->reqlen = n; /* Gate readers onto the mount point one at a time */ for(;;) { lock(&m->lk); if(m->rip == 0) break; unlock(&m->lk); sleep(&r->r, rpcattn, r); if(r->done){ poperror(); mntflushfree(m, r); return; } } m->rip = up; unlock(&m->lk); while(r->done == 0) { if(mntrpcread(m, r) < 0) error(Emountrpc); mountmux(m, r); } mntgate(m); poperror(); mntflushfree(m, r); } static int doread(Mnt *m, int len) { Block *b; while(qlen(m->q) < len){ b = devtab[m->c->type]->bread(m->c, m->msize, 0); if(b == nil) return -1; if(BLEN(b) == 0){ freeblist(b); return -1; } qaddlist(m->q, b); } return 0; } int mntrpcread(Mnt *m, Mntrpc *r) { int i, t, len, hlen; Block *b, **l, *nb; r->reply.type = 0; r->reply.tag = 0; /* read at least length, type, and tag and pullup to a single block */ if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0) return -1; nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ); /* read in the rest of the message, avoid rediculous (for now) message sizes */ len = GBIT32(nb->rp); if(len > m->msize){ qdiscard(m->q, qlen(m->q)); return -1; } if(doread(m, len) < 0) return -1; /* pullup the header (i.e. everything except data) */ t = nb->rp[BIT32SZ]; switch(t){ case Rread: hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ; break; default: hlen = len; break; } nb = pullupqueue(m->q, hlen); if(convM2S(nb->rp, len, &r->reply) <= 0){ /* bad message, dump it */ print("mntrpcread: convM2S failed\n"); qdiscard(m->q, len); return -1; } /* hang the data off of the fcall struct */ l = &r->b; *l = nil; do { b = qremove(m->q); if(hlen > 0){ b->rp += hlen; len -= hlen; hlen = 0; } i = BLEN(b); if(i <= len){ len -= i; *l = b; l = &(b->next); } else { /* split block and put unused bit back */ nb = allocb(i-len); memmove(nb->wp, b->rp+len, i-len); b->wp = b->rp+len; nb->wp += i-len; qputback(m->q, nb); *l = b; return 0; } }while(len > 0); return 0; } void mntgate(Mnt *m) { Mntrpc *q; lock(&m->lk); m->rip = 0; for(q = m->queue; q; q = q->list) { if(q->done == 0) if(wakeup(&q->r)) break; } unlock(&m->lk); } void mountmux(Mnt *m, Mntrpc *r) { Mntrpc **l, *q; lock(&m->lk); l = &m->queue; for(q = *l; q; q = q->list) { /* look for a reply to a message */ if(q->request.tag == r->reply.tag) { *l = q->list; if(q != r) { /* * Completed someone else. * Trade pointers to receive buffer. */ q->reply = r->reply; q->b = r->b; r->b = nil; } q->done = 1; unlock(&m->lk); if(mntstats != 0) (*mntstats)(q->request.type, m->c, q->stime, q->reqlen + r->replen); if(q != r) wakeup(&q->r); return; } l = &q->list; } unlock(&m->lk); print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type); } /* * Create a new flush request and chain the previous * requests from it */ Mntrpc* mntflushalloc(Mntrpc *r, ulong iounit) { Mntrpc *fr; fr = mntralloc(0, iounit); fr->request.type = Tflush; if(r->request.type == Tflush) fr->request.oldtag = r->request.oldtag; else fr->request.oldtag = r->request.tag; fr->flushed = r; return fr; } /* * Free a chain of flushes. Remove each unanswered * flush and the original message from the unanswered * request queue. Mark the original message as done * and if it hasn't been answered set the reply to to * Rflush. */ void mntflushfree(Mnt *m, Mntrpc *r) { Mntrpc *fr; while(r){ fr = r->flushed; if(!r->done){ r->reply.type = Rflush; mntqrm(m, r); } if(fr) mntfree(r); r = fr; } } int alloctag(void) { int i, j; ulong v; for(i = 0; i < NMASK; i++){ v = mntalloc.tagmask[i]; if(v == ~0) continue; for(j = 0; j < 1<>TAGSHIFT] &= ~(1<<(t&TAGMASK)); } Mntrpc* mntralloc(Chan *c, ulong msize) { Mntrpc *new; lock(&mntalloc.lk); new = mntalloc.rpcfree; if(new == nil){ new = malloc(sizeof(Mntrpc)); if(new == nil) { unlock(&mntalloc.lk); exhausted("mount rpc header"); } /* * The header is split from the data buffer as * mountmux may swap the buffer with another header. */ new->rpc = mallocz(msize, 0); if(new->rpc == nil){ free(new); unlock(&mntalloc.lk); exhausted("mount rpc buffer"); } new->rpclen = msize; new->request.tag = alloctag(); } else { mntalloc.rpcfree = new->list; mntalloc.nrpcfree--; if(new->rpclen < msize){ free(new->rpc); new->rpc = mallocz(msize, 0); if(new->rpc == nil){ free(new); mntalloc.nrpcused--; unlock(&mntalloc.lk); exhausted("mount rpc buffer"); } new->rpclen = msize; } } mntalloc.nrpcused++; unlock(&mntalloc.lk); new->c = c; new->done = 0; new->flushed = nil; new->b = nil; return new; } void mntfree(Mntrpc *r) { if(r->b != nil) freeblist(r->b); lock(&mntalloc.lk); if(mntalloc.nrpcfree >= 10){ free(r->rpc); free(r); freetag(r->request.tag); } else{ r->list = mntalloc.rpcfree; mntalloc.rpcfree = r; mntalloc.nrpcfree++; } mntalloc.nrpcused--; unlock(&mntalloc.lk); } void mntqrm(Mnt *m, Mntrpc *r) { Mntrpc **l, *f; lock(&m->lk); r->done = 1; l = &m->queue; for(f = *l; f; f = f->list) { if(f == r) { *l = r->list; break; } l = &f->list; } unlock(&m->lk); } Mnt* mntchk(Chan *c) { Mnt *m; /* This routine is mostly vestiges of prior lives; now it's just sanity checking */ if(c->mchan == nil) panic("mntchk 1: nil mchan c %s\n", c2name(c)); m = c->mchan->mux; if(m == nil) print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan)); /* * Was it closed and reused (was error(Eshutdown); now, it can't happen) */ if(m->id == 0 || m->id >= c->dev) panic("mntchk 3: can't happen"); return m; } /* * Rewrite channel type and dev for in-flight data to * reflect local values. These entries are known to be * the first two in the Dir encoding after the count. */ void mntdirfix(uchar *dirbuf, Chan *c) { uint r; r = devtab[c->type]->dc; dirbuf += BIT16SZ; /* skip count */ PBIT16(dirbuf, r); dirbuf += BIT16SZ; PBIT32(dirbuf, c->dev); } int rpcattn(void *v) { Mntrpc *r; r = v; return r->done || r->m->rip == 0; } Dev mntdevtab = { 'M', "mnt", mntreset, devinit, devshutdown, mntattach, mntwalk, mntstat, mntopen, mntcreate, mntclose, mntread, devbread, mntwrite, devbwrite, mntremove, mntwstat, }; drawterm-20170818/kern/devmouse.c000066400000000000000000000073271314554504700165660ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "draw.h" #include "memdraw.h" #include "screen.h" int mousequeue = 1; Mouseinfo mouse; Cursorinfo cursor; static int mousechanged(void*); enum{ Qdir, Qcursor, Qmouse }; Dirtab mousedir[]={ ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "cursor", {Qcursor}, 0, 0666, "mouse", {Qmouse}, 0, 0666, }; #define NMOUSE (sizeof(mousedir)/sizeof(Dirtab)) static Chan* mouseattach(char *spec) { return devattach('m', spec); } static Walkqid* mousewalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, mousedir, NMOUSE, devgen); } static int mousestat(Chan *c, uchar *db, int n) { return devstat(c, db, n, mousedir, NMOUSE, devgen); } static Chan* mouseopen(Chan *c, int omode) { switch((long)c->qid.path){ case Qdir: if(omode != OREAD) error(Eperm); break; case Qmouse: lock(&mouse.lk); if(mouse.open){ unlock(&mouse.lk); error(Einuse); } mouse.open = 1; unlock(&mouse.lk); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } void mouseclose(Chan *c) { if(!(c->flag&COPEN)) return; switch((long)c->qid.path) { case Qmouse: lock(&mouse.lk); mouse.open = 0; unlock(&mouse.lk); cursorarrow(); } } long mouseread(Chan *c, void *va, long n, vlong offset) { char buf[4*12+1]; uchar *p; int i, nn; ulong msec; /* static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 }; */ p = va; switch((long)c->qid.path){ case Qdir: return devdirread(c, va, n, mousedir, NMOUSE, devgen); case Qcursor: if(offset != 0) return 0; if(n < 2*4+2*2*16) error(Eshort); n = 2*4+2*2*16; lock(&cursor.lk); BPLONG(p+0, cursor.offset.x); BPLONG(p+4, cursor.offset.y); memmove(p+8, cursor.clr, 2*16); memmove(p+40, cursor.set, 2*16); unlock(&cursor.lk); return n; case Qmouse: while(mousechanged(0) == 0) sleep(&mouse.r, mousechanged, 0); lock(&screen.lk); if(screen.reshaped) { screen.reshaped = 0; sprint(buf, "t%11d %11d", 0, ticks()); if(n > 1+2*12) n = 1+2*12; memmove(va, buf, n); unlock(&screen.lk); return n; } unlock(&screen.lk); lock(&mouse.lk); i = mouse.ri; nn = (mouse.wi + Mousequeue - i) % Mousequeue; if(nn < 1) panic("empty mouse queue"); msec = ticks(); while(nn > 1) { if(mouse.queue[i].msec + Mousewindow > msec) break; i = (i+1)%Mousequeue; nn--; } sprint(buf, "m%11d %11d %11d %11d", mouse.queue[i].xy.x, mouse.queue[i].xy.y, mouse.queue[i].buttons, mouse.queue[i].msec); mouse.ri = (i+1)%Mousequeue; unlock(&mouse.lk); if(n > 1+4*12) n = 1+4*12; memmove(va, buf, n); return n; } return 0; } long mousewrite(Chan *c, void *va, long n, vlong offset) { char *p; Point pt; char buf[64]; USED(offset); p = va; switch((long)c->qid.path){ case Qdir: error(Eisdir); case Qcursor: if(n < 2*4+2*2*16){ cursorarrow(); }else{ n = 2*4+2*2*16; lock(&cursor.lk); cursor.offset.x = BGLONG(p+0); cursor.offset.y = BGLONG(p+4); memmove(cursor.clr, p+8, 2*16); memmove(cursor.set, p+40, 2*16); unlock(&cursor.lk); setcursor(); } return n; case Qmouse: if(n > sizeof buf-1) n = sizeof buf -1; memmove(buf, va, n); buf[n] = 0; p = 0; pt.x = strtoul(buf+1, &p, 0); if(p == 0) error(Eshort); pt.y = strtoul(p, 0, 0); if(ptinrect(pt, gscreen->r)) mouseset(pt); return n; } error(Egreg); return -1; } int mousechanged(void *a) { USED(a); return mouse.ri != mouse.wi || screen.reshaped; } Dev mousedevtab = { 'm', "mouse", devreset, devinit, devshutdown, mouseattach, mousewalk, mousestat, mouseopen, devcreate, mouseclose, mouseread, devbread, mousewrite, devbwrite, devremove, devwstat, }; drawterm-20170818/kern/devpipe.c000066400000000000000000000134471314554504700163730ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "netif.h" typedef struct Pipe Pipe; struct Pipe { QLock lk; Pipe *next; int ref; ulong path; Queue *q[2]; int qref[2]; }; struct { Lock lk; ulong path; } pipealloc; enum { Qdir, Qdata0, Qdata1, }; Dirtab pipedir[] = { ".", {Qdir,0,QTDIR}, 0, DMDIR|0500, "data", {Qdata0}, 0, 0600, "data1", {Qdata1}, 0, 0600, }; #define NPIPEDIR 3 static void pipeinit(void) { if(conf.pipeqsize == 0){ if(conf.nmach > 1) conf.pipeqsize = 256*1024; else conf.pipeqsize = 32*1024; } } /* * create a pipe, no streams are created until an open */ static Chan* pipeattach(char *spec) { Pipe *p; Chan *c; c = devattach('|', spec); p = malloc(sizeof(Pipe)); if(p == 0) exhausted("memory"); p->ref = 1; p->q[0] = qopen(conf.pipeqsize, 0, 0, 0); if(p->q[0] == 0){ free(p); exhausted("memory"); } p->q[1] = qopen(conf.pipeqsize, 0, 0, 0); if(p->q[1] == 0){ free(p->q[0]); free(p); exhausted("memory"); } lock(&pipealloc.lk); p->path = ++pipealloc.path; unlock(&pipealloc.lk); mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR); c->aux = p; c->dev = 0; return c; } static int pipegen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp) { Qid q; int len; Pipe *p; USED(name); if(i == DEVDOTDOT){ devdir(c, c->qid, "#|", 0, eve, DMDIR|0555, dp); return 1; } i++; /* skip . */ if(tab==0 || i>=ntab) return -1; tab += i; p = c->aux; switch((ulong)tab->qid.path){ case Qdata0: len = qlen(p->q[0]); break; case Qdata1: len = qlen(p->q[1]); break; default: len = tab->length; break; } mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE); devdir(c, q, tab->name, len, eve, tab->perm, dp); return 1; } static Walkqid* pipewalk(Chan *c, Chan *nc, char **name, int nname) { Walkqid *wq; Pipe *p; wq = devwalk(c, nc, name, nname, pipedir, NPIPEDIR, pipegen); if(wq != nil && wq->clone != nil && wq->clone != c){ p = c->aux; qlock(&p->lk); p->ref++; if(c->flag & COPEN){ print("channel open in pipewalk\n"); switch(NETTYPE(c->qid.path)){ case Qdata0: p->qref[0]++; break; case Qdata1: p->qref[1]++; break; } } qunlock(&p->lk); } return wq; } static int pipestat(Chan *c, uchar *db, int n) { Pipe *p; Dir dir; p = c->aux; switch(NETTYPE(c->qid.path)){ case Qdir: devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir); break; case Qdata0: devdir(c, c->qid, "data", qlen(p->q[0]), eve, 0600, &dir); break; case Qdata1: devdir(c, c->qid, "data1", qlen(p->q[1]), eve, 0600, &dir); break; default: panic("pipestat"); } n = convD2M(&dir, db, n); if(n < BIT16SZ) error(Eshortstat); return n; } /* * if the stream doesn't exist, create it */ static Chan* pipeopen(Chan *c, int omode) { Pipe *p; if(c->qid.type & QTDIR){ if(omode != OREAD) error(Ebadarg); c->mode = omode; c->flag |= COPEN; c->offset = 0; return c; } p = c->aux; qlock(&p->lk); switch(NETTYPE(c->qid.path)){ case Qdata0: p->qref[0]++; break; case Qdata1: p->qref[1]++; break; } qunlock(&p->lk); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; c->iounit = qiomaxatomic; return c; } static void pipeclose(Chan *c) { Pipe *p; p = c->aux; qlock(&p->lk); if(c->flag & COPEN){ /* * closing either side hangs up the stream */ switch(NETTYPE(c->qid.path)){ case Qdata0: p->qref[0]--; if(p->qref[0] == 0){ qhangup(p->q[1], 0); qclose(p->q[0]); } break; case Qdata1: p->qref[1]--; if(p->qref[1] == 0){ qhangup(p->q[0], 0); qclose(p->q[1]); } break; } } /* * if both sides are closed, they are reusable */ if(p->qref[0] == 0 && p->qref[1] == 0){ qreopen(p->q[0]); qreopen(p->q[1]); } /* * free the structure on last close */ p->ref--; if(p->ref == 0){ qunlock(&p->lk); free(p->q[0]); free(p->q[1]); free(p); } else qunlock(&p->lk); } static long piperead(Chan *c, void *va, long n, vlong offset) { Pipe *p; USED(offset); p = c->aux; switch(NETTYPE(c->qid.path)){ case Qdir: return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen); case Qdata0: return qread(p->q[0], va, n); case Qdata1: return qread(p->q[1], va, n); default: panic("piperead"); } return -1; /* not reached */ } static Block* pipebread(Chan *c, long n, ulong offset) { Pipe *p; p = c->aux; switch(NETTYPE(c->qid.path)){ case Qdata0: return qbread(p->q[0], n); case Qdata1: return qbread(p->q[1], n); } return devbread(c, n, offset); } /* * a write to a closed pipe causes a note to be sent to * the process. */ static long pipewrite(Chan *c, void *va, long n, vlong offset) { Pipe *p; USED(offset); if(!islo()) print("pipewrite hi %lux\n", getcallerpc(&c)); if(waserror()) { /* avoid notes when pipe is a mounted queue */ if((c->flag & CMSG) == 0) postnote(up, 1, "sys: write on closed pipe", NUser); nexterror(); } p = c->aux; switch(NETTYPE(c->qid.path)){ case Qdata0: n = qwrite(p->q[1], va, n); break; case Qdata1: n = qwrite(p->q[0], va, n); break; default: panic("pipewrite"); } poperror(); return n; } static long pipebwrite(Chan *c, Block *bp, ulong offset) { long n; Pipe *p; USED(offset); if(waserror()) { /* avoid notes when pipe is a mounted queue */ if((c->flag & CMSG) == 0) postnote(up, 1, "sys: write on closed pipe", NUser); nexterror(); } p = c->aux; switch(NETTYPE(c->qid.path)){ case Qdata0: n = qbwrite(p->q[1], bp); break; case Qdata1: n = qbwrite(p->q[0], bp); break; default: n = 0; panic("pipebwrite"); } poperror(); return n; } Dev pipedevtab = { '|', "pipe", devreset, pipeinit, devshutdown, pipeattach, pipewalk, pipestat, pipeopen, devcreate, pipeclose, piperead, pipebread, pipewrite, pipebwrite, devremove, devwstat, }; drawterm-20170818/kern/devroot.c000066400000000000000000000112231314554504700164070ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" enum { Qdir = 0, Qboot = 0x1000, Qmnt = 0x2000, Qfactotum, Nrootfiles = 32, Nbootfiles = 32, Nmntfiles = 2, }; typedef struct Dirlist Dirlist; struct Dirlist { uint base; Dirtab *dir; uchar **data; int ndir; int mdir; }; static Dirtab rootdir[Nrootfiles] = { "#/", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "boot", {Qboot, 0, QTDIR}, 0, DMDIR|0555, "mnt", {Qmnt, 0, QTDIR}, 0, DMDIR|0555, }; static uchar *rootdata[Nrootfiles]; static Dirlist rootlist = { 0, rootdir, rootdata, 3, Nrootfiles }; static Dirtab bootdir[Nbootfiles] = { "boot", {Qboot, 0, QTDIR}, 0, DMDIR|0555, }; static uchar *bootdata[Nbootfiles]; static Dirlist bootlist = { Qboot, bootdir, bootdata, 1, Nbootfiles }; static uchar *mntdata[Nmntfiles]; static Dirtab mntdir[Nmntfiles] = { "mnt", {Qmnt, 0, QTDIR}, 0, DMDIR|0555, "factotum", {Qfactotum, 0, QTDIR}, 0, DMDIR|0555, }; static Dirlist mntlist = { Qmnt, mntdir, mntdata, 2, Nmntfiles }; /* * add a file to the list */ static void addlist(Dirlist *l, char *name, uchar *contents, ulong len, int perm) { Dirtab *d; if(l->ndir >= l->mdir) panic("too many root files"); l->data[l->ndir] = contents; d = &l->dir[l->ndir]; strcpy(d->name, name); d->length = len; d->perm = perm; d->qid.type = 0; d->qid.vers = 0; d->qid.path = ++l->ndir + l->base; if(perm & DMDIR) d->qid.type |= QTDIR; } /* * add a root file */ void addbootfile(char *name, uchar *contents, ulong len) { addlist(&bootlist, name, contents, len, 0555); } /* * add a root directory */ static void addrootdir(char *name) { addlist(&rootlist, name, nil, 0, DMDIR|0555); } static void rootreset(void) { addrootdir("bin"); addrootdir("dev"); addrootdir("env"); addrootdir("fd"); addrootdir("net"); addrootdir("net.alt"); addrootdir("proc"); addrootdir("root"); addrootdir("srv"); } static Chan* rootattach(char *spec) { return devattach('/', spec); } static int rootgen(Chan *c, char *name, Dirtab *dirt, int ndirt, int s, Dir *dp) { int t; Dirtab *d; Dirlist *l; USED(dirt); USED(ndirt); switch((int)c->qid.path){ case Qdir: if(s == DEVDOTDOT){ Qid tqiddir = {Qdir, 0, QTDIR}; devdir(c, tqiddir, "#/", 0, eve, 0555, dp); return 1; } return devgen(c, name, rootlist.dir, rootlist.ndir, s, dp); case Qmnt: if(s == DEVDOTDOT){ Qid tqiddir = {Qdir, 0, QTDIR}; devdir(c, tqiddir, "#/", 0, eve, 0555, dp); return 1; } return devgen(c, name, mntlist.dir, mntlist.ndir, s, dp); case Qboot: if(s == DEVDOTDOT){ Qid tqiddir = {Qdir, 0, QTDIR}; devdir(c, tqiddir, "#/", 0, eve, 0555, dp); return 1; } return devgen(c, name, bootlist.dir, bootlist.ndir, s, dp); default: if(s == DEVDOTDOT){ Qid tqiddir = {Qdir, 0, QTDIR}; tqiddir.path = c->qid.path&0xF000; devdir(c, tqiddir, "#/", 0, eve, 0555, dp); return 1; } if(s != 0) return -1; switch((int)c->qid.path & 0xF000){ case Qdir: t = c->qid.path-1; l = &rootlist; break; case Qboot: t = c->qid.path - Qboot - 1; l = &bootlist; break; case Qmnt: t = c->qid.path - Qmnt - 1; l = &mntlist; break; default: return -1; } if(t >= l->ndir) return -1; if(t < 0){ print("rootgen %llud %d %d\n", c->qid.path, s, t); panic("whoops"); } d = &l->dir[t]; devdir(c, d->qid, d->name, d->length, eve, d->perm, dp); return 1; } return -1; } static Walkqid* rootwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, nil, 0, rootgen); } static int rootstat(Chan *c, uchar *dp, int n) { return devstat(c, dp, n, nil, 0, rootgen); } static Chan* rootopen(Chan *c, int omode) { return devopen(c, omode, nil, 0, devgen); } /* * sysremove() knows this is a nop */ static void rootclose(Chan *c) { USED(c); } static long rootread(Chan *c, void *buf, long n, vlong off) { ulong t; Dirtab *d; Dirlist *l; uchar *data; ulong offset = off; t = c->qid.path; switch(t){ case Qdir: case Qboot: case Qmnt: return devdirread(c, buf, n, nil, 0, rootgen); } if(t&Qboot) l = &bootlist; else if(t&Qmnt) l = &mntlist; else l = &bootlist; t &= 0xFFF; t--; if(t >= l->ndir) error(Egreg); d = &l->dir[t]; data = l->data[t]; if(offset >= d->length) return 0; if(offset+n > d->length) n = d->length - offset; memmove(buf, data+offset, n); return n; } static long rootwrite(Chan *c, void *v, long n, vlong o) { USED(c); USED(v); USED(n); USED(o); error(Egreg); return 0; } Dev rootdevtab = { '/', "root", rootreset, devinit, devshutdown, rootattach, rootwalk, rootstat, rootopen, devcreate, rootclose, rootread, devbread, rootwrite, devbwrite, devremove, devwstat, }; drawterm-20170818/kern/devssl.c000066400000000000000000000635251314554504700162410ustar00rootroot00000000000000/* * devssl - secure sockets layer */ #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "libsec.h" #define NOSPOOKS 1 typedef struct OneWay OneWay; struct OneWay { QLock q; QLock ctlq; void *state; /* encryption state */ int slen; /* hash data length */ uchar *secret; /* secret */ ulong mid; /* message id */ }; enum { /* connection states */ Sincomplete= 0, Sclear= 1, Sencrypting= 2, Sdigesting= 4, Sdigenc= Sencrypting|Sdigesting, /* encryption algorithms */ Noencryption= 0, DESCBC= 1, DESECB= 2, RC4= 3 }; typedef struct Dstate Dstate; struct Dstate { Chan *c; /* io channel */ uchar state; /* state of connection */ int ref; /* serialized by dslock for atomic destroy */ uchar encryptalg; /* encryption algorithm */ ushort blocklen; /* blocking length */ ushort diglen; /* length of digest */ DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); /* hash func */ /* for SSL format */ int max; /* maximum unpadded data per msg */ int maxpad; /* maximum padded data per msg */ /* input side */ OneWay in; Block *processed; Block *unprocessed; /* output side */ OneWay out; /* protections */ char *user; int perm; }; enum { Maxdmsg= 1<<16, Maxdstate= 128, /* must be a power of 2 */ }; Lock dslock; int dshiwat; char *dsname[Maxdstate]; Dstate *dstate[Maxdstate]; char *encalgs; char *hashalgs; enum{ Qtopdir = 1, /* top level directory */ Qprotodir, Qclonus, Qconvdir, /* directory for a conversation */ Qdata, Qctl, Qsecretin, Qsecretout, Qencalgs, Qhashalgs, }; #define TYPE(x) ((x).path & 0xf) #define CONV(x) (((x).path >> 5)&(Maxdstate-1)) #define QID(c, y) (((c)<<5) | (y)) static void ensure(Dstate*, Block**, int); static void consume(Block**, uchar*, int); static void setsecret(OneWay*, uchar*, int); static Block* encryptb(Dstate*, Block*, int); static Block* decryptb(Dstate*, Block*); static Block* digestb(Dstate*, Block*, int); static void checkdigestb(Dstate*, Block*); static Chan* buftochan(char*); static void sslhangup(Dstate*); static Dstate* dsclone(Chan *c); static void dsnew(Chan *c, Dstate **); static long sslput(Dstate *s, Block * volatile b); char *sslnames[] = { /* unused */ 0, /* topdir */ 0, /* protodir */ 0, "clone", /* convdir */ 0, "data", "ctl", "secretin", "secretout", "encalgs", "hashalgs", }; static int sslgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp) { Qid q; Dstate *ds; char name[16], *p, *nm; int ft; USED(n); USED(nd); USED(d); q.type = QTFILE; q.vers = 0; ft = TYPE(c->qid); switch(ft) { case Qtopdir: if(s == DEVDOTDOT){ q.path = QID(0, Qtopdir); q.type = QTDIR; devdir(c, q, "#D", 0, eve, 0555, dp); return 1; } if(s > 0) return -1; q.path = QID(0, Qprotodir); q.type = QTDIR; devdir(c, q, "ssl", 0, eve, 0555, dp); return 1; case Qprotodir: if(s == DEVDOTDOT){ q.path = QID(0, Qtopdir); q.type = QTDIR; devdir(c, q, ".", 0, eve, 0555, dp); return 1; } if(s < dshiwat) { q.path = QID(s, Qconvdir); q.type = QTDIR; ds = dstate[s]; if(ds != 0) nm = ds->user; else nm = eve; if(dsname[s] == nil){ sprint(name, "%d", s); kstrdup(&dsname[s], name); } devdir(c, q, dsname[s], 0, nm, 0555, dp); return 1; } if(s > dshiwat) return -1; q.path = QID(0, Qclonus); devdir(c, q, "clone", 0, eve, 0555, dp); return 1; case Qconvdir: if(s == DEVDOTDOT){ q.path = QID(0, Qprotodir); q.type = QTDIR; devdir(c, q, "ssl", 0, eve, 0555, dp); return 1; } ds = dstate[CONV(c->qid)]; if(ds != 0) nm = ds->user; else nm = eve; switch(s) { default: return -1; case 0: q.path = QID(CONV(c->qid), Qctl); p = "ctl"; break; case 1: q.path = QID(CONV(c->qid), Qdata); p = "data"; break; case 2: q.path = QID(CONV(c->qid), Qsecretin); p = "secretin"; break; case 3: q.path = QID(CONV(c->qid), Qsecretout); p = "secretout"; break; case 4: q.path = QID(CONV(c->qid), Qencalgs); p = "encalgs"; break; case 5: q.path = QID(CONV(c->qid), Qhashalgs); p = "hashalgs"; break; } devdir(c, q, p, 0, nm, 0660, dp); return 1; case Qclonus: devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp); return 1; default: ds = dstate[CONV(c->qid)]; if(ds != 0) nm = ds->user; else nm = eve; devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp); return 1; } return -1; } static Chan* sslattach(char *spec) { Chan *c; c = devattach('D', spec); c->qid.path = QID(0, Qtopdir); c->qid.vers = 0; c->qid.type = QTDIR; return c; } static Walkqid* sslwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, nil, 0, sslgen); } static int sslstat(Chan *c, uchar *db, int n) { return devstat(c, db, n, nil, 0, sslgen); } static Chan* sslopen(Chan *c, int omode) { Dstate *s, **pp; int perm; int ft; perm = 0; omode &= 3; switch(omode) { case OREAD: perm = 4; break; case OWRITE: perm = 2; break; case ORDWR: perm = 6; break; } ft = TYPE(c->qid); switch(ft) { default: panic("sslopen"); case Qtopdir: case Qprotodir: case Qconvdir: if(omode != OREAD) error(Eperm); break; case Qclonus: s = dsclone(c); if(s == 0) error(Enodev); break; case Qctl: case Qdata: case Qsecretin: case Qsecretout: if(waserror()) { unlock(&dslock); nexterror(); } lock(&dslock); pp = &dstate[CONV(c->qid)]; s = *pp; if(s == 0) dsnew(c, pp); else { if((perm & (s->perm>>6)) != perm && (strcmp(up->user, s->user) != 0 || (perm & s->perm) != perm)) error(Eperm); s->ref++; } unlock(&dslock); poperror(); break; case Qencalgs: case Qhashalgs: if(omode != OREAD) error(Eperm); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } static int sslwstat(Chan *c, uchar *db, int n) { Dir *dir; Dstate *s; int m; s = dstate[CONV(c->qid)]; if(s == 0) error(Ebadusefd); if(strcmp(s->user, up->user) != 0) error(Eperm); dir = smalloc(sizeof(Dir)+n); m = convM2D(db, n, &dir[0], (char*)&dir[1]); if(m == 0){ free(dir); error(Eshortstat); } if(!emptystr(dir->uid)) kstrdup(&s->user, dir->uid); if(dir->mode != ~0) s->perm = dir->mode; free(dir); return m; } static void sslclose(Chan *c) { Dstate *s; int ft; ft = TYPE(c->qid); switch(ft) { case Qctl: case Qdata: case Qsecretin: case Qsecretout: if((c->flag & COPEN) == 0) break; s = dstate[CONV(c->qid)]; if(s == 0) break; lock(&dslock); if(--s->ref > 0) { unlock(&dslock); break; } dstate[CONV(c->qid)] = 0; unlock(&dslock); if(s->user != nil) free(s->user); sslhangup(s); if(s->c) cclose(s->c); if(s->in.secret) free(s->in.secret); if(s->out.secret) free(s->out.secret); if(s->in.state) free(s->in.state); if(s->out.state) free(s->out.state); free(s); } } /* * make sure we have at least 'n' bytes in list 'l' */ static void ensure(Dstate *s, Block **l, int n) { int sofar, i; Block *b, *bl; sofar = 0; for(b = *l; b; b = b->next){ sofar += BLEN(b); if(sofar >= n) return; l = &b->next; } while(sofar < n){ bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0); if(bl == 0) nexterror(); *l = bl; i = 0; for(b = bl; b; b = b->next){ i += BLEN(b); l = &b->next; } if(i == 0) error(Ehungup); sofar += i; } } /* * copy 'n' bytes from 'l' into 'p' and free * the bytes in 'l' */ static void consume(Block **l, uchar *p, int n) { Block *b; int i; for(; *l && n > 0; n -= i){ b = *l; i = BLEN(b); if(i > n) i = n; memmove(p, b->rp, i); b->rp += i; p += i; if(BLEN(b) < 0) panic("consume"); if(BLEN(b)) break; *l = b->next; freeb(b); } } /* * give back n bytes static void regurgitate(Dstate *s, uchar *p, int n) { Block *b; if(n <= 0) return; b = s->unprocessed; if(s->unprocessed == nil || b->rp - b->base < n) { b = allocb(n); memmove(b->wp, p, n); b->wp += n; b->next = s->unprocessed; s->unprocessed = b; } else { b->rp -= n; memmove(b->rp, p, n); } } */ /* * remove at most n bytes from the queue, if discard is set * dump the remainder */ static Block* qtake(Block **l, int n, int discard) { Block *nb, *b, *first; int i; first = *l; for(b = first; b; b = b->next){ i = BLEN(b); if(i == n){ if(discard){ freeblist(b->next); *l = 0; } else *l = b->next; b->next = 0; return first; } else if(i > n){ i -= n; if(discard){ freeblist(b->next); b->wp -= i; *l = 0; } else { nb = allocb(i); memmove(nb->wp, b->rp+n, i); nb->wp += i; b->wp -= i; nb->next = b->next; *l = nb; } b->next = 0; if(BLEN(b) < 0) panic("qtake"); return first; } else n -= i; if(BLEN(b) < 0) panic("qtake"); } *l = 0; return first; } /* * We can't let Eintr's lose data since the program * doing the read may be able to handle it. The only * places Eintr is possible is during the read's in consume. * Therefore, we make sure we can always put back the bytes * consumed before the last ensure. */ static Block* sslbread(Chan *c, long n, ulong o) { Dstate * volatile s; Block *b; uchar consumed[3], *p; int toconsume; int len, pad; USED(o); s = dstate[CONV(c->qid)]; if(s == 0) panic("sslbread"); if(s->state == Sincomplete) error(Ebadusefd); qlock(&s->in.q); if(waserror()){ qunlock(&s->in.q); nexterror(); } if(s->processed == 0){ /* * Read in the whole message. Until we've got it all, * it stays on s->unprocessed, so that if we get Eintr, * we'll pick up where we left off. */ ensure(s, &s->unprocessed, 3); s->unprocessed = pullupblock(s->unprocessed, 2); p = s->unprocessed->rp; if(p[0] & 0x80){ len = ((p[0] & 0x7f)<<8) | p[1]; ensure(s, &s->unprocessed, len); pad = 0; toconsume = 2; } else { s->unprocessed = pullupblock(s->unprocessed, 3); len = ((p[0] & 0x3f)<<8) | p[1]; pad = p[2]; if(pad > len){ print("pad %d buf len %d\n", pad, len); error("bad pad in ssl message"); } toconsume = 3; } ensure(s, &s->unprocessed, toconsume+len); /* skip header */ consume(&s->unprocessed, consumed, toconsume); /* grab the next message and decode/decrypt it */ b = qtake(&s->unprocessed, len, 0); if(blocklen(b) != len) print("devssl: sslbread got wrong count %d != %d", blocklen(b), len); if(waserror()){ qunlock(&s->in.ctlq); if(b != nil) freeb(b); nexterror(); } qlock(&s->in.ctlq); switch(s->state){ case Sencrypting: if(b == nil) error("ssl message too short (encrypting)"); b = decryptb(s, b); break; case Sdigesting: b = pullupblock(b, s->diglen); if(b == nil) error("ssl message too short (digesting)"); checkdigestb(s, b); pullblock(&b, s->diglen); len -= s->diglen; break; case Sdigenc: b = decryptb(s, b); b = pullupblock(b, s->diglen); if(b == nil) error("ssl message too short (dig+enc)"); checkdigestb(s, b); pullblock(&b, s->diglen); len -= s->diglen; break; } /* remove pad */ if(pad) s->processed = qtake(&b, len - pad, 1); else s->processed = b; b = nil; s->in.mid++; qunlock(&s->in.ctlq); poperror(); } /* return at most what was asked for */ b = qtake(&s->processed, n, 0); qunlock(&s->in.q); poperror(); return b; } static long sslread(Chan *c, void *a, long n, vlong off) { Block * volatile b; Block *nb; uchar *va; int i; char buf[128]; ulong offset = off; int ft; if(c->qid.type & QTDIR) return devdirread(c, a, n, 0, 0, sslgen); ft = TYPE(c->qid); switch(ft) { default: error(Ebadusefd); case Qctl: ft = CONV(c->qid); sprint(buf, "%d", ft); return readstr(offset, a, n, buf); case Qdata: b = sslbread(c, n, offset); break; case Qencalgs: return readstr(offset, a, n, encalgs); break; case Qhashalgs: return readstr(offset, a, n, hashalgs); break; } if(waserror()){ freeblist(b); nexterror(); } n = 0; va = a; for(nb = b; nb; nb = nb->next){ i = BLEN(nb); memmove(va+n, nb->rp, i); n += i; } freeblist(b); poperror(); return n; } /* * this algorithm doesn't have to be great since we're just * trying to obscure the block fill */ static void randfill(uchar *buf, int len) { while(len-- > 0) *buf++ = fastrand(); } static long sslbwrite(Chan *c, Block *b, ulong o) { Dstate * volatile s; long rv; USED(o); s = dstate[CONV(c->qid)]; if(s == nil) panic("sslbwrite"); if(s->state == Sincomplete){ freeb(b); error(Ebadusefd); } /* lock so split writes won't interleave */ if(waserror()){ qunlock(&s->out.q); nexterror(); } qlock(&s->out.q); rv = sslput(s, b); poperror(); qunlock(&s->out.q); return rv; } /* * use SSL record format, add in count, digest and/or encrypt. * the write is interruptable. if it is interrupted, we'll * get out of sync with the far side. not much we can do about * it since we don't know if any bytes have been written. */ static long sslput(Dstate *s, Block * volatile b) { Block *nb; int h, n, m, pad, rv; uchar *p; int offset; if(waserror()){ iprint("error: %s\n", up->errstr); if(b != nil) free(b); nexterror(); } rv = 0; while(b != nil){ m = n = BLEN(b); h = s->diglen + 2; /* trim to maximum block size */ pad = 0; if(m > s->max){ m = s->max; } else if(s->blocklen != 1){ pad = (m + s->diglen)%s->blocklen; if(pad){ if(m > s->maxpad){ pad = 0; m = s->maxpad; } else { pad = s->blocklen - pad; h++; } } } rv += m; if(m != n){ nb = allocb(m + h + pad); memmove(nb->wp + h, b->rp, m); nb->wp += m + h; b->rp += m; } else { /* add header space */ nb = padblock(b, h); b = 0; } m += s->diglen; /* SSL style count */ if(pad){ nb = padblock(nb, -pad); randfill(nb->wp, pad); nb->wp += pad; m += pad; p = nb->rp; p[0] = (m>>8); p[1] = m; p[2] = pad; offset = 3; } else { p = nb->rp; p[0] = (m>>8) | 0x80; p[1] = m; offset = 2; } switch(s->state){ case Sencrypting: nb = encryptb(s, nb, offset); break; case Sdigesting: nb = digestb(s, nb, offset); break; case Sdigenc: nb = digestb(s, nb, offset); nb = encryptb(s, nb, offset); break; } s->out.mid++; m = BLEN(nb); devtab[s->c->type]->bwrite(s->c, nb, s->c->offset); s->c->offset += m; } poperror(); return rv; } static void setsecret(OneWay *w, uchar *secret, int n) { if(w->secret) free(w->secret); w->secret = smalloc(n); memmove(w->secret, secret, n); w->slen = n; } static void initDESkey(OneWay *w) { if(w->state){ free(w->state); w->state = 0; } w->state = smalloc(sizeof(DESstate)); if(w->slen >= 16) setupDESstate(w->state, w->secret, w->secret+8); else if(w->slen >= 8) setupDESstate(w->state, w->secret, 0); else error("secret too short"); } /* * 40 bit DES is the same as 56 bit DES. However, * 16 bits of the key are masked to zero. */ static void initDESkey_40(OneWay *w) { uchar key[8]; if(w->state){ free(w->state); w->state = 0; } if(w->slen >= 8){ memmove(key, w->secret, 8); key[0] &= 0x0f; key[2] &= 0x0f; key[4] &= 0x0f; key[6] &= 0x0f; } w->state = malloc(sizeof(DESstate)); if(w->slen >= 16) setupDESstate(w->state, key, w->secret+8); else if(w->slen >= 8) setupDESstate(w->state, key, 0); else error("secret too short"); } static void initRC4key(OneWay *w) { if(w->state){ free(w->state); w->state = 0; } w->state = smalloc(sizeof(RC4state)); setupRC4state(w->state, w->secret, w->slen); } /* * 40 bit RC4 is the same as n-bit RC4. However, * we ignore all but the first 40 bits of the key. */ static void initRC4key_40(OneWay *w) { if(w->state){ free(w->state); w->state = 0; } if(w->slen > 5) w->slen = 5; w->state = malloc(sizeof(RC4state)); setupRC4state(w->state, w->secret, w->slen); } /* * 128 bit RC4 is the same as n-bit RC4. However, * we ignore all but the first 128 bits of the key. */ static void initRC4key_128(OneWay *w) { if(w->state){ free(w->state); w->state = 0; } if(w->slen > 16) w->slen = 16; w->state = malloc(sizeof(RC4state)); setupRC4state(w->state, w->secret, w->slen); } typedef struct Hashalg Hashalg; struct Hashalg { char *name; int diglen; DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); }; Hashalg hashtab[] = { { "md4", MD4dlen, md4, }, { "md5", MD5dlen, md5, }, { "sha1", SHA1dlen, sha1, }, { "sha", SHA1dlen, sha1, }, { 0 } }; static int parsehashalg(char *p, Dstate *s) { Hashalg *ha; for(ha = hashtab; ha->name; ha++){ if(strcmp(p, ha->name) == 0){ s->hf = ha->hf; s->diglen = ha->diglen; s->state &= ~Sclear; s->state |= Sdigesting; return 0; } } return -1; } typedef struct Encalg Encalg; struct Encalg { char *name; int blocklen; int alg; void (*keyinit)(OneWay*); }; #ifdef NOSPOOKS Encalg encrypttab[] = { { "descbc", 8, DESCBC, initDESkey, }, /* DEPRECATED -- use des_56_cbc */ { "desecb", 8, DESECB, initDESkey, }, /* DEPRECATED -- use des_56_ecb */ { "des_56_cbc", 8, DESCBC, initDESkey, }, { "des_56_ecb", 8, DESECB, initDESkey, }, { "des_40_cbc", 8, DESCBC, initDESkey_40, }, { "des_40_ecb", 8, DESECB, initDESkey_40, }, { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */ { "rc4_256", 1, RC4, initRC4key, }, { "rc4_128", 1, RC4, initRC4key_128, }, { "rc4_40", 1, RC4, initRC4key_40, }, { 0 } }; #else Encalg encrypttab[] = { { "des_40_cbc", 8, DESCBC, initDESkey_40, }, { "des_40_ecb", 8, DESECB, initDESkey_40, }, { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */ { "rc4_40", 1, RC4, initRC4key_40, }, { 0 } }; #endif /* NOSPOOKS */ static int parseencryptalg(char *p, Dstate *s) { Encalg *ea; for(ea = encrypttab; ea->name; ea++){ if(strcmp(p, ea->name) == 0){ s->encryptalg = ea->alg; s->blocklen = ea->blocklen; (*ea->keyinit)(&s->in); (*ea->keyinit)(&s->out); s->state &= ~Sclear; s->state |= Sencrypting; return 0; } } return -1; } static long sslwrite(Chan *c, void *a, long n, vlong o) { Dstate * volatile s; Block * volatile b; int m, t; char *p, *np, *e, buf[128]; uchar *x; USED(o); s = dstate[CONV(c->qid)]; if(s == 0) panic("sslwrite"); t = TYPE(c->qid); if(t == Qdata){ if(s->state == Sincomplete) error(Ebadusefd); /* lock should a write gets split over multiple records */ if(waserror()){ qunlock(&s->out.q); nexterror(); } qlock(&s->out.q); p = a; if(0) iprint("write %d %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n", n, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); e = p + n; do { m = e - p; if(m > s->max) m = s->max; b = allocb(m); if(waserror()){ freeb(b); nexterror(); } memmove(b->wp, p, m); poperror(); b->wp += m; sslput(s, b); p += m; } while(p < e); p = a; if(0) iprint("wrote %d %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n", n, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); poperror(); qunlock(&s->out.q); return n; } /* mutex with operations using what we're about to change */ if(waserror()){ qunlock(&s->in.ctlq); qunlock(&s->out.q); nexterror(); } qlock(&s->in.ctlq); qlock(&s->out.q); switch(t){ default: panic("sslwrite"); case Qsecretin: setsecret(&s->in, a, n); goto out; case Qsecretout: setsecret(&s->out, a, n); goto out; case Qctl: break; } if(n >= sizeof(buf)) error("arg too long"); strncpy(buf, a, n); buf[n] = 0; p = strchr(buf, '\n'); if(p) *p = 0; p = strchr(buf, ' '); if(p) *p++ = 0; if(strcmp(buf, "fd") == 0){ s->c = buftochan(p); /* default is clear (msg delimiters only) */ s->state = Sclear; s->blocklen = 1; s->diglen = 0; s->maxpad = s->max = (1<<15) - s->diglen - 1; s->in.mid = 0; s->out.mid = 0; } else if(strcmp(buf, "alg") == 0 && p != 0){ s->blocklen = 1; s->diglen = 0; if(s->c == 0) error("must set fd before algorithm"); s->state = Sclear; s->maxpad = s->max = (1<<15) - s->diglen - 1; if(strcmp(p, "clear") == 0){ goto out; } if(s->in.secret && s->out.secret == 0) setsecret(&s->out, s->in.secret, s->in.slen); if(s->out.secret && s->in.secret == 0) setsecret(&s->in, s->out.secret, s->out.slen); if(s->in.secret == 0 || s->out.secret == 0) error("algorithm but no secret"); s->hf = 0; s->encryptalg = Noencryption; s->blocklen = 1; for(;;){ np = strchr(p, ' '); if(np) *np++ = 0; if(parsehashalg(p, s) < 0) if(parseencryptalg(p, s) < 0) error("bad algorithm"); if(np == 0) break; p = np; } if(s->hf == 0 && s->encryptalg == Noencryption) error("bad algorithm"); if(s->blocklen != 1){ s->max = (1<<15) - s->diglen - 1; s->max -= s->max % s->blocklen; s->maxpad = (1<<14) - s->diglen - 1; s->maxpad -= s->maxpad % s->blocklen; } else s->maxpad = s->max = (1<<15) - s->diglen - 1; } else if(strcmp(buf, "secretin") == 0 && p != 0) { m = (strlen(p)*3)/2; x = smalloc(m); t = dec64(x, m, p, strlen(p)); setsecret(&s->in, x, t); free(x); } else if(strcmp(buf, "secretout") == 0 && p != 0) { m = (strlen(p)*3)/2 + 1; x = smalloc(m); t = dec64(x, m, p, strlen(p)); setsecret(&s->out, x, t); free(x); } else error(Ebadarg); out: qunlock(&s->in.ctlq); qunlock(&s->out.q); poperror(); return n; } static void sslinit(void) { struct Encalg *e; struct Hashalg *h; int n; char *cp; n = 1; for(e = encrypttab; e->name != nil; e++) n += strlen(e->name) + 1; cp = encalgs = smalloc(n); for(e = encrypttab;;){ strcpy(cp, e->name); cp += strlen(e->name); e++; if(e->name == nil) break; *cp++ = ' '; } *cp = 0; n = 1; for(h = hashtab; h->name != nil; h++) n += strlen(h->name) + 1; cp = hashalgs = smalloc(n); for(h = hashtab;;){ strcpy(cp, h->name); cp += strlen(h->name); h++; if(h->name == nil) break; *cp++ = ' '; } *cp = 0; } Dev ssldevtab = { 'D', "ssl", devreset, sslinit, devshutdown, sslattach, sslwalk, sslstat, sslopen, devcreate, sslclose, sslread, sslbread, sslwrite, sslbwrite, devremove, sslwstat, }; static Block* encryptb(Dstate *s, Block *b, int offset) { uchar *p, *ep, *p2, *ip, *eip; DESstate *ds; switch(s->encryptalg){ case DESECB: ds = s->out.state; ep = b->rp + BLEN(b); for(p = b->rp + offset; p < ep; p += 8) block_cipher(ds->expanded, p, 0); break; case DESCBC: ds = s->out.state; ep = b->rp + BLEN(b); for(p = b->rp + offset; p < ep; p += 8){ p2 = p; ip = ds->ivec; for(eip = ip+8; ip < eip; ) *p2++ ^= *ip++; block_cipher(ds->expanded, p, 0); memmove(ds->ivec, p, 8); } break; case RC4: rc4(s->out.state, b->rp + offset, BLEN(b) - offset); break; } return b; } static Block* decryptb(Dstate *s, Block *bin) { Block *b, **l; uchar *p, *ep, *tp, *ip, *eip; DESstate *ds; uchar tmp[8]; int i; l = &bin; for(b = bin; b; b = b->next){ /* make sure we have a multiple of s->blocklen */ if(s->blocklen > 1){ i = BLEN(b); if(i % s->blocklen){ *l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen)); if(b == 0) error("ssl encrypted message too short"); } } l = &b->next; /* decrypt */ switch(s->encryptalg){ case DESECB: ds = s->in.state; ep = b->rp + BLEN(b); for(p = b->rp; p < ep; p += 8) block_cipher(ds->expanded, p, 1); break; case DESCBC: ds = s->in.state; ep = b->rp + BLEN(b); for(p = b->rp; p < ep;){ memmove(tmp, p, 8); block_cipher(ds->expanded, p, 1); tp = tmp; ip = ds->ivec; for(eip = ip+8; ip < eip; ){ *p++ ^= *ip; *ip++ = *tp++; } } break; case RC4: rc4(s->in.state, b->rp, BLEN(b)); break; } } return bin; } static Block* digestb(Dstate *s, Block *b, int offset) { uchar *p; DigestState ss; uchar msgid[4]; ulong n, h; OneWay *w; w = &s->out; memset(&ss, 0, sizeof(ss)); h = s->diglen + offset; n = BLEN(b) - h; /* hash secret + message */ (*s->hf)(w->secret, w->slen, 0, &ss); (*s->hf)(b->rp + h, n, 0, &ss); /* hash message id */ p = msgid; n = w->mid; *p++ = n>>24; *p++ = n>>16; *p++ = n>>8; *p = n; (*s->hf)(msgid, 4, b->rp + offset, &ss); return b; } static void checkdigestb(Dstate *s, Block *bin) { uchar *p; DigestState ss; uchar msgid[4]; int n, h; OneWay *w; uchar digest[128]; Block *b; w = &s->in; memset(&ss, 0, sizeof(ss)); /* hash secret */ (*s->hf)(w->secret, w->slen, 0, &ss); /* hash message */ h = s->diglen; for(b = bin; b; b = b->next){ n = BLEN(b) - h; if(n < 0) panic("checkdigestb"); (*s->hf)(b->rp + h, n, 0, &ss); h = 0; } /* hash message id */ p = msgid; n = w->mid; *p++ = n>>24; *p++ = n>>16; *p++ = n>>8; *p = n; (*s->hf)(msgid, 4, digest, &ss); if(memcmp(digest, bin->rp, s->diglen) != 0) error("bad digest"); } /* get channel associated with an fd */ static Chan* buftochan(char *p) { Chan *c; int fd; if(p == 0) error(Ebadarg); fd = strtoul(p, 0, 0); if(fd < 0) error(Ebadarg); c = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ if(devtab[c->type] == &ssldevtab){ cclose(c); error("cannot ssl encrypt devssl files"); } return c; } /* hand up a digest connection */ static void sslhangup(Dstate *s) { Block *b; qlock(&s->in.q); for(b = s->processed; b; b = s->processed){ s->processed = b->next; freeb(b); } if(s->unprocessed){ freeb(s->unprocessed); s->unprocessed = 0; } s->state = Sincomplete; qunlock(&s->in.q); } static Dstate* dsclone(Chan *ch) { int i; Dstate *ret; if(waserror()) { unlock(&dslock); nexterror(); } lock(&dslock); ret = nil; for(i=0; i= dshiwat) dshiwat++; memset(s, 0, sizeof(*s)); s->state = Sincomplete; s->ref = 1; kstrdup(&s->user, up->user); s->perm = 0660; t = TYPE(ch->qid); if(t == Qclonus) t = Qctl; ch->qid.path = QID(pp - dstate, t); ch->qid.vers = 0; } drawterm-20170818/kern/devtab.c000066400000000000000000000010401314554504700161660ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" extern Dev consdevtab; extern Dev rootdevtab; extern Dev pipedevtab; extern Dev ssldevtab; extern Dev tlsdevtab; extern Dev mousedevtab; extern Dev drawdevtab; extern Dev ipdevtab; extern Dev fsdevtab; extern Dev mntdevtab; extern Dev lfddevtab; extern Dev audiodevtab; Dev *devtab[] = { &rootdevtab, &consdevtab, &pipedevtab, &ssldevtab, &tlsdevtab, &mousedevtab, &drawdevtab, &ipdevtab, &fsdevtab, &mntdevtab, &lfddevtab, &audiodevtab, 0 }; drawterm-20170818/kern/devtls.c000066400000000000000000001303771314554504700162420ustar00rootroot00000000000000/* * devtls - record layer for transport layer security 1.0 and secure sockets layer 3.0 */ #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "libsec.h" typedef struct OneWay OneWay; typedef struct Secret Secret; typedef struct TlsRec TlsRec; typedef struct TlsErrs TlsErrs; enum { Statlen= 1024, /* max. length of status or stats message */ /* buffer limits */ MaxRecLen = 1<<14, /* max payload length of a record layer message */ MaxCipherRecLen = MaxRecLen + 2048, RecHdrLen = 5, MaxMacLen = SHA1dlen, /* protocol versions we can accept */ TLSVersion = 0x0301, SSL3Version = 0x0300, ProtocolVersion = 0x0301, /* maximum version we speak */ MinProtoVersion = 0x0300, /* limits on version we accept */ MaxProtoVersion = 0x03ff, /* connection states */ SHandshake = 1 << 0, /* doing handshake */ SOpen = 1 << 1, /* application data can be sent */ SRClose = 1 << 2, /* remote side has closed down */ SLClose = 1 << 3, /* sent a close notify alert */ SAlert = 1 << 5, /* sending or sent a fatal alert */ SError = 1 << 6, /* some sort of error has occured */ SClosed = 1 << 7, /* it is all over */ /* record types */ RChangeCipherSpec = 20, RAlert, RHandshake, RApplication, SSL2ClientHello = 1, HSSL2ClientHello = 9, /* local convention; see tlshand.c */ /* alerts */ ECloseNotify = 0, EUnexpectedMessage = 10, EBadRecordMac = 20, EDecryptionFailed = 21, ERecordOverflow = 22, EDecompressionFailure = 30, EHandshakeFailure = 40, ENoCertificate = 41, EBadCertificate = 42, EUnsupportedCertificate = 43, ECertificateRevoked = 44, ECertificateExpired = 45, ECertificateUnknown = 46, EIllegalParameter = 47, EUnknownCa = 48, EAccessDenied = 49, EDecodeError = 50, EDecryptError = 51, EExportRestriction = 60, EProtocolVersion = 70, EInsufficientSecurity = 71, EInternalError = 80, EUserCanceled = 90, ENoRenegotiation = 100, EMAX = 256 }; struct Secret { char *encalg; /* name of encryption alg */ char *hashalg; /* name of hash alg */ int (*enc)(Secret*, uchar*, int); int (*dec)(Secret*, uchar*, int); int (*unpad)(uchar*, int, int); DigestState *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); int block; /* encryption block len, 0 if none */ int maclen; void *enckey; uchar mackey[MaxMacLen]; }; struct OneWay { QLock io; /* locks io access */ QLock seclock; /* locks secret paramaters */ ulong seq; Secret *sec; /* cipher in use */ Secret *new; /* cipher waiting for enable */ }; struct TlsRec { Chan *c; /* io channel */ int ref; /* serialized by tdlock for atomic destroy */ int version; /* version of the protocol we are speaking */ char verset; /* version has been set */ char opened; /* opened command every issued? */ char err[ERRMAX]; /* error message to return to handshake requests */ vlong handin; /* bytes communicated by the record layer */ vlong handout; vlong datain; vlong dataout; Lock statelk; int state; int debug; /* record layer mac functions for different protocol versions */ void (*packMac)(Secret*, uchar*, uchar*, uchar*, uchar*, int, uchar*); /* input side -- protected by in.io */ OneWay in; Block *processed; /* next bunch of application data */ Block *unprocessed; /* data read from c but not parsed into records */ /* handshake queue */ Lock hqlock; /* protects hqref, alloc & free of handq, hprocessed */ int hqref; Queue *handq; /* queue of handshake messages */ Block *hprocessed; /* remainder of last block read from handq */ QLock hqread; /* protects reads for hprocessed, handq */ /* output side */ OneWay out; /* protections */ char *user; int perm; }; struct TlsErrs{ int err; int sslerr; int tlserr; int fatal; char *msg; }; static TlsErrs tlserrs[] = { {ECloseNotify, ECloseNotify, ECloseNotify, 0, "close notify"}, {EUnexpectedMessage, EUnexpectedMessage, EUnexpectedMessage, 1, "unexpected message"}, {EBadRecordMac, EBadRecordMac, EBadRecordMac, 1, "bad record mac"}, {EDecryptionFailed, EIllegalParameter, EDecryptionFailed, 1, "decryption failed"}, {ERecordOverflow, EIllegalParameter, ERecordOverflow, 1, "record too long"}, {EDecompressionFailure, EDecompressionFailure, EDecompressionFailure, 1, "decompression failed"}, {EHandshakeFailure, EHandshakeFailure, EHandshakeFailure, 1, "could not negotiate acceptable security parameters"}, {ENoCertificate, ENoCertificate, ECertificateUnknown, 1, "no appropriate certificate available"}, {EBadCertificate, EBadCertificate, EBadCertificate, 1, "corrupted or invalid certificate"}, {EUnsupportedCertificate, EUnsupportedCertificate, EUnsupportedCertificate, 1, "unsupported certificate type"}, {ECertificateRevoked, ECertificateRevoked, ECertificateRevoked, 1, "revoked certificate"}, {ECertificateExpired, ECertificateExpired, ECertificateExpired, 1, "expired certificate"}, {ECertificateUnknown, ECertificateUnknown, ECertificateUnknown, 1, "unacceptable certificate"}, {EIllegalParameter, EIllegalParameter, EIllegalParameter, 1, "illegal parameter"}, {EUnknownCa, EHandshakeFailure, EUnknownCa, 1, "unknown certificate authority"}, {EAccessDenied, EHandshakeFailure, EAccessDenied, 1, "access denied"}, {EDecodeError, EIllegalParameter, EDecodeError, 1, "error decoding message"}, {EDecryptError, EIllegalParameter, EDecryptError, 1, "error decrypting message"}, {EExportRestriction, EHandshakeFailure, EExportRestriction, 1, "export restriction violated"}, {EProtocolVersion, EIllegalParameter, EProtocolVersion, 1, "protocol version not supported"}, {EInsufficientSecurity, EHandshakeFailure, EInsufficientSecurity, 1, "stronger security routines required"}, {EInternalError, EHandshakeFailure, EInternalError, 1, "internal error"}, {EUserCanceled, ECloseNotify, EUserCanceled, 0, "handshake canceled by user"}, {ENoRenegotiation, EUnexpectedMessage, ENoRenegotiation, 0, "no renegotiation"}, }; enum { /* max. open tls connections */ MaxTlsDevs = 1024 }; static Lock tdlock; static int tdhiwat; static int maxtlsdevs = 128; static TlsRec **tlsdevs; static char **trnames; static char *encalgs; static char *hashalgs; enum{ Qtopdir = 1, /* top level directory */ Qprotodir, Qclonus, Qencalgs, Qhashalgs, Qconvdir, /* directory for a conversation */ Qdata, Qctl, Qhand, Qstatus, Qstats, }; #define TYPE(x) ((x).path & 0xf) #define CONV(x) (((x).path >> 5)&(MaxTlsDevs-1)) #define QID(c, y) (((c)<<5) | (y)) static void checkstate(TlsRec *, int, int); static void ensure(TlsRec*, Block**, int); static void consume(Block**, uchar*, int); static Chan* buftochan(char*); static void tlshangup(TlsRec*); static void tlsError(TlsRec*, char *); static void alertHand(TlsRec*, char *); static TlsRec *newtls(Chan *c); static TlsRec *mktlsrec(void); static DigestState*sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); static DigestState*sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); static DigestState*nomac(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); static void sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac); static void tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac); static void put64(uchar *p, vlong x); static void put32(uchar *p, u32int); static void put24(uchar *p, int); static void put16(uchar *p, int); /* static u32int get32(uchar *p); */ static int get16(uchar *p); static void tlsSetState(TlsRec *tr, int new, int old); static void rcvAlert(TlsRec *tr, int err); static void sendAlert(TlsRec *tr, int err); static void rcvError(TlsRec *tr, int err, char *msg, ...); static int rc4enc(Secret *sec, uchar *buf, int n); static int des3enc(Secret *sec, uchar *buf, int n); static int des3dec(Secret *sec, uchar *buf, int n); static int noenc(Secret *sec, uchar *buf, int n); static int sslunpad(uchar *buf, int n, int block); static int tlsunpad(uchar *buf, int n, int block); static void freeSec(Secret *sec); static char *tlsstate(int s); static void pdump(int, void*, char*); static char *tlsnames[] = { /* unused */ 0, /* topdir */ 0, /* protodir */ 0, "clone", "encalgs", "hashalgs", /* convdir */ 0, "data", "ctl", "hand", "status", "stats", }; static int convdir[] = { Qctl, Qdata, Qhand, Qstatus, Qstats }; static int tlsgen(Chan *c, char*unused1, Dirtab *unused2, int unused3, int s, Dir *dp) { Qid q; TlsRec *tr; char *name, *nm; int perm, t; q.vers = 0; q.type = QTFILE; t = TYPE(c->qid); switch(t) { case Qtopdir: if(s == DEVDOTDOT){ q.path = QID(0, Qtopdir); q.type = QTDIR; devdir(c, q, "#a", 0, eve, 0555, dp); return 1; } if(s > 0) return -1; q.path = QID(0, Qprotodir); q.type = QTDIR; devdir(c, q, "tls", 0, eve, 0555, dp); return 1; case Qprotodir: if(s == DEVDOTDOT){ q.path = QID(0, Qtopdir); q.type = QTDIR; devdir(c, q, ".", 0, eve, 0555, dp); return 1; } if(s < 3){ switch(s) { default: return -1; case 0: q.path = QID(0, Qclonus); break; case 1: q.path = QID(0, Qencalgs); break; case 2: q.path = QID(0, Qhashalgs); break; } perm = 0444; if(TYPE(q) == Qclonus) perm = 0555; devdir(c, q, tlsnames[TYPE(q)], 0, eve, perm, dp); return 1; } s -= 3; if(s >= tdhiwat) return -1; q.path = QID(s, Qconvdir); q.type = QTDIR; lock(&tdlock); tr = tlsdevs[s]; if(tr != nil) nm = tr->user; else nm = eve; if((name = trnames[s]) == nil){ name = trnames[s] = smalloc(16); sprint(name, "%d", s); } devdir(c, q, name, 0, nm, 0555, dp); unlock(&tdlock); return 1; case Qconvdir: if(s == DEVDOTDOT){ q.path = QID(0, Qprotodir); q.type = QTDIR; devdir(c, q, "tls", 0, eve, 0555, dp); return 1; } if(s < 0 || s >= nelem(convdir)) return -1; lock(&tdlock); tr = tlsdevs[CONV(c->qid)]; if(tr != nil){ nm = tr->user; perm = tr->perm; }else{ perm = 0; nm = eve; } t = convdir[s]; if(t == Qstatus || t == Qstats) perm &= 0444; q.path = QID(CONV(c->qid), t); devdir(c, q, tlsnames[t], 0, nm, perm, dp); unlock(&tdlock); return 1; case Qclonus: case Qencalgs: case Qhashalgs: perm = 0444; if(t == Qclonus) perm = 0555; devdir(c, c->qid, tlsnames[t], 0, eve, perm, dp); return 1; default: lock(&tdlock); tr = tlsdevs[CONV(c->qid)]; if(tr != nil){ nm = tr->user; perm = tr->perm; }else{ perm = 0; nm = eve; } if(t == Qstatus || t == Qstats) perm &= 0444; devdir(c, c->qid, tlsnames[t], 0, nm, perm, dp); unlock(&tdlock); return 1; } return -1; } static Chan* tlsattach(char *spec) { Chan *c; c = devattach('a', spec); c->qid.path = QID(0, Qtopdir); c->qid.type = QTDIR; c->qid.vers = 0; return c; } static Walkqid* tlswalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, nil, 0, tlsgen); } static int tlsstat(Chan *c, uchar *db, int n) { return devstat(c, db, n, nil, 0, tlsgen); } static Chan* tlsopen(Chan *c, int omode) { TlsRec *tr, **pp; int t, perm; perm = 0; omode &= 3; switch(omode) { case OREAD: perm = 4; break; case OWRITE: perm = 2; break; case ORDWR: perm = 6; break; } t = TYPE(c->qid); switch(t) { default: panic("tlsopen"); case Qtopdir: case Qprotodir: case Qconvdir: if(omode != OREAD) error(Eperm); break; case Qclonus: tr = newtls(c); if(tr == nil) error(Enodev); break; case Qctl: case Qdata: case Qhand: case Qstatus: case Qstats: if((t == Qstatus || t == Qstats) && omode != OREAD) error(Eperm); if(waserror()) { unlock(&tdlock); nexterror(); } lock(&tdlock); pp = &tlsdevs[CONV(c->qid)]; tr = *pp; if(tr == nil) error("must open connection using clone"); if((perm & (tr->perm>>6)) != perm && (strcmp(up->user, tr->user) != 0 || (perm & tr->perm) != perm)) error(Eperm); if(t == Qhand){ if(waserror()){ unlock(&tr->hqlock); nexterror(); } lock(&tr->hqlock); if(tr->handq != nil) error(Einuse); tr->handq = qopen(2 * MaxCipherRecLen, 0, 0, nil); if(tr->handq == nil) error("cannot allocate handshake queue"); tr->hqref = 1; unlock(&tr->hqlock); poperror(); } tr->ref++; unlock(&tdlock); poperror(); break; case Qencalgs: case Qhashalgs: if(omode != OREAD) error(Eperm); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; c->iounit = qiomaxatomic; return c; } static int tlswstat(Chan *c, uchar *dp, int n) { Dir *d; TlsRec *tr; int rv; d = nil; if(waserror()){ free(d); unlock(&tdlock); nexterror(); } lock(&tdlock); tr = tlsdevs[CONV(c->qid)]; if(tr == nil) error(Ebadusefd); if(strcmp(tr->user, up->user) != 0) error(Eperm); d = smalloc(n + sizeof *d); rv = convM2D(dp, n, &d[0], (char*) &d[1]); if(rv == 0) error(Eshortstat); if(!emptystr(d->uid)) kstrdup(&tr->user, d->uid); if(d->mode != (u32int)~0UL) tr->perm = d->mode; free(d); poperror(); unlock(&tdlock); return rv; } static void dechandq(TlsRec *tr) { lock(&tr->hqlock); if(--tr->hqref == 0){ if(tr->handq != nil){ qfree(tr->handq); tr->handq = nil; } if(tr->hprocessed != nil){ freeb(tr->hprocessed); tr->hprocessed = nil; } } unlock(&tr->hqlock); } static void tlsclose(Chan *c) { TlsRec *tr; int t; t = TYPE(c->qid); switch(t) { case Qctl: case Qdata: case Qhand: case Qstatus: case Qstats: if((c->flag & COPEN) == 0) break; tr = tlsdevs[CONV(c->qid)]; if(tr == nil) break; if(t == Qhand) dechandq(tr); lock(&tdlock); if(--tr->ref > 0) { unlock(&tdlock); return; } tlsdevs[CONV(c->qid)] = nil; unlock(&tdlock); if(tr->c != nil && !waserror()){ checkstate(tr, 0, SOpen|SHandshake|SRClose); sendAlert(tr, ECloseNotify); poperror(); } tlshangup(tr); if(tr->c != nil) cclose(tr->c); freeSec(tr->in.sec); freeSec(tr->in.new); freeSec(tr->out.sec); freeSec(tr->out.new); free(tr->user); free(tr); break; } } /* * make sure we have at least 'n' bytes in list 'l' */ static void ensure(TlsRec *s, Block **l, int n) { int sofar, i; Block *b, *bl; sofar = 0; for(b = *l; b; b = b->next){ sofar += BLEN(b); if(sofar >= n) return; l = &b->next; } while(sofar < n){ bl = devtab[s->c->type]->bread(s->c, MaxCipherRecLen + RecHdrLen, 0); if(bl == 0) error(Ehungup); *l = bl; i = 0; for(b = bl; b; b = b->next){ i += BLEN(b); l = &b->next; } if(i == 0) error(Ehungup); sofar += i; } if(s->debug) pprint("ensure read %d\n", sofar); } /* * copy 'n' bytes from 'l' into 'p' and free * the bytes in 'l' */ static void consume(Block **l, uchar *p, int n) { Block *b; int i; for(; *l && n > 0; n -= i){ b = *l; i = BLEN(b); if(i > n) i = n; memmove(p, b->rp, i); b->rp += i; p += i; if(BLEN(b) < 0) panic("consume"); if(BLEN(b)) break; *l = b->next; freeb(b); } } /* * give back n bytes */ static void regurgitate(TlsRec *s, uchar *p, int n) { Block *b; if(n <= 0) return; b = s->unprocessed; if(s->unprocessed == nil || b->rp - b->base < n) { b = allocb(n); memmove(b->wp, p, n); b->wp += n; b->next = s->unprocessed; s->unprocessed = b; } else { b->rp -= n; memmove(b->rp, p, n); } } /* * remove at most n bytes from the queue */ static Block* qgrab(Block **l, int n) { Block *bb, *b; int i; b = *l; if(BLEN(b) == n){ *l = b->next; b->next = nil; return b; } i = 0; for(bb = b; bb != nil && i < n; bb = bb->next) i += BLEN(bb); if(i > n) i = n; bb = allocb(i); consume(l, bb->wp, i); bb->wp += i; return bb; } static void tlsclosed(TlsRec *tr, int new) { lock(&tr->statelk); if(tr->state == SOpen || tr->state == SHandshake) tr->state = new; else if((new | tr->state) == (SRClose|SLClose)) tr->state = SClosed; unlock(&tr->statelk); alertHand(tr, "close notify"); } /* * read and process one tls record layer message * must be called with tr->in.io held * We can't let Eintrs lose data, since doing so will get * us out of sync with the sender and break the reliablity * of the channel. Eintr only happens during the reads in * consume. Therefore we put back any bytes consumed before * the last call to ensure. */ static void tlsrecread(TlsRec *tr) { OneWay *volatile in; Block *volatile b; uchar *p, seq[8], header[RecHdrLen], hmac[MD5dlen]; int volatile nconsumed; int len, type, ver, unpad_len; nconsumed = 0; if(waserror()){ if(strcmp(up->errstr, Eintr) == 0 && !waserror()){ regurgitate(tr, header, nconsumed); poperror(); }else tlsError(tr, "channel error"); nexterror(); } ensure(tr, &tr->unprocessed, RecHdrLen); consume(&tr->unprocessed, header, RecHdrLen); if(tr->debug)pprint("consumed %d header\n", RecHdrLen); nconsumed = RecHdrLen; if((tr->handin == 0) && (header[0] & 0x80)){ /* Cope with an SSL3 ClientHello expressed in SSL2 record format. This is sent by some clients that we must interoperate with, such as Java's JSSE and Microsoft's Internet Explorer. */ len = (get16(header) & ~0x8000) - 3; type = header[2]; ver = get16(header + 3); if(type != SSL2ClientHello || len < 22) rcvError(tr, EProtocolVersion, "invalid initial SSL2-like message"); }else{ /* normal SSL3 record format */ type = header[0]; ver = get16(header+1); len = get16(header+3); } if(ver != tr->version && (tr->verset || ver < MinProtoVersion || ver > MaxProtoVersion)) rcvError(tr, EProtocolVersion, "devtls expected ver=%x%s, saw (len=%d) type=%x ver=%x '%.12s'", tr->version, tr->verset?"/set":"", len, type, ver, (char*)header); if(len > MaxCipherRecLen || len < 0) rcvError(tr, ERecordOverflow, "record message too long %d", len); ensure(tr, &tr->unprocessed, len); nconsumed = 0; poperror(); /* * If an Eintr happens after this, we'll get out of sync. * Make sure nothing we call can sleep. * Errors are ok, as they kill the connection. * Luckily, allocb won't sleep, it'll just error out. */ b = nil; if(waserror()){ if(b != nil) freeb(b); tlsError(tr, "channel error"); nexterror(); } b = qgrab(&tr->unprocessed, len); if(tr->debug) pprint("consumed unprocessed %d\n", len); in = &tr->in; if(waserror()){ qunlock(&in->seclock); nexterror(); } qlock(&in->seclock); p = b->rp; if(in->sec != nil) { /* to avoid Canvel-Hiltgen-Vaudenay-Vuagnoux attack, all errors here should look alike, including timing of the response. */ unpad_len = (*in->sec->dec)(in->sec, p, len); if(unpad_len >= in->sec->maclen) len = unpad_len - in->sec->maclen; if(tr->debug) pprint("decrypted %d\n", unpad_len); if(tr->debug) pdump(unpad_len, p, "decrypted:"); /* update length */ put16(header+3, len); put64(seq, in->seq); in->seq++; (*tr->packMac)(in->sec, in->sec->mackey, seq, header, p, len, hmac); if(unpad_len < in->sec->maclen) rcvError(tr, EBadRecordMac, "short record mac"); if(memcmp(hmac, p+len, in->sec->maclen) != 0) rcvError(tr, EBadRecordMac, "record mac mismatch"); b->wp = b->rp + len; } qunlock(&in->seclock); poperror(); if(len < 0) rcvError(tr, EDecodeError, "runt record message"); switch(type) { default: rcvError(tr, EIllegalParameter, "invalid record message 0x%x", type); break; case RChangeCipherSpec: if(len != 1 || p[0] != 1) rcvError(tr, EDecodeError, "invalid change cipher spec"); qlock(&in->seclock); if(in->new == nil){ qunlock(&in->seclock); rcvError(tr, EUnexpectedMessage, "unexpected change cipher spec"); } freeSec(in->sec); in->sec = in->new; in->new = nil; in->seq = 0; qunlock(&in->seclock); break; case RAlert: if(len != 2) rcvError(tr, EDecodeError, "invalid alert"); if(p[0] == 2) rcvAlert(tr, p[1]); if(p[0] != 1) rcvError(tr, EIllegalParameter, "invalid alert fatal code"); /* * propate non-fatal alerts to handshaker */ if(p[1] == ECloseNotify) { tlsclosed(tr, SRClose); if(tr->opened) error("tls hungup"); error("close notify"); } if(p[1] == ENoRenegotiation) alertHand(tr, "no renegotiation"); else if(p[1] == EUserCanceled) alertHand(tr, "handshake canceled by user"); else rcvError(tr, EIllegalParameter, "invalid alert code"); break; case RHandshake: /* * don't worry about dropping the block * qbwrite always queues even if flow controlled and interrupted. * * if there isn't any handshaker, ignore the request, * but notify the other side we are doing so. */ lock(&tr->hqlock); if(tr->handq != nil){ tr->hqref++; unlock(&tr->hqlock); if(waserror()){ dechandq(tr); nexterror(); } b = padblock(b, 1); *b->rp = RHandshake; qbwrite(tr->handq, b); b = nil; poperror(); dechandq(tr); }else{ unlock(&tr->hqlock); if(tr->verset && tr->version != SSL3Version && !waserror()){ sendAlert(tr, ENoRenegotiation); poperror(); } } break; case SSL2ClientHello: lock(&tr->hqlock); if(tr->handq != nil){ tr->hqref++; unlock(&tr->hqlock); if(waserror()){ dechandq(tr); nexterror(); } /* Pass the SSL2 format data, so that the handshake code can compute the correct checksums. HSSL2ClientHello = HandshakeType 9 is unused in RFC2246. */ b = padblock(b, 8); b->rp[0] = RHandshake; b->rp[1] = HSSL2ClientHello; put24(&b->rp[2], len+3); b->rp[5] = SSL2ClientHello; put16(&b->rp[6], ver); qbwrite(tr->handq, b); b = nil; poperror(); dechandq(tr); }else{ unlock(&tr->hqlock); if(tr->verset && tr->version != SSL3Version && !waserror()){ sendAlert(tr, ENoRenegotiation); poperror(); } } break; case RApplication: if(!tr->opened) rcvError(tr, EUnexpectedMessage, "application message received before handshake completed"); if(BLEN(b) > 0){ tr->processed = b; b = nil; } break; } if(b != nil) freeb(b); poperror(); } /* * got a fatal alert message */ static void rcvAlert(TlsRec *tr, int err) { char *s; int i; s = "unknown error"; for(i=0; i < nelem(tlserrs); i++){ if(tlserrs[i].err == err){ s = tlserrs[i].msg; break; } } if(tr->debug) pprint("rcvAlert: %s\n", s); tlsError(tr, s); if(!tr->opened) error(s); error("tls error"); } /* * found an error while decoding the input stream */ static void rcvError(TlsRec *tr, int err, char *fmt, ...) { char msg[ERRMAX]; va_list arg; va_start(arg, fmt); vseprint(msg, msg+sizeof(msg), fmt, arg); va_end(arg); if(tr->debug) pprint("rcvError: %s\n", msg); sendAlert(tr, err); if(!tr->opened) error(msg); error("tls error"); } /* * make sure the next hand operation returns with a 'msg' error */ static void alertHand(TlsRec *tr, char *msg) { Block *b; int n; lock(&tr->hqlock); if(tr->handq == nil){ unlock(&tr->hqlock); return; } tr->hqref++; unlock(&tr->hqlock); n = strlen(msg); if(waserror()){ dechandq(tr); nexterror(); } b = allocb(n + 2); *b->wp++ = RAlert; memmove(b->wp, msg, n + 1); b->wp += n + 1; qbwrite(tr->handq, b); poperror(); dechandq(tr); } static void checkstate(TlsRec *tr, int ishand, int ok) { int state; lock(&tr->statelk); state = tr->state; unlock(&tr->statelk); if(state & ok) return; switch(state){ case SHandshake: case SOpen: break; case SError: case SAlert: if(ishand) error(tr->err); error("tls error"); case SRClose: case SLClose: case SClosed: error("tls hungup"); } error("tls improperly configured"); } static Block* tlsbread(Chan *c, long n, ulong offset) { int ty; Block *b; TlsRec *volatile tr; ty = TYPE(c->qid); switch(ty) { default: return devbread(c, n, offset); case Qhand: case Qdata: break; } tr = tlsdevs[CONV(c->qid)]; if(tr == nil) panic("tlsbread"); if(waserror()){ qunlock(&tr->in.io); nexterror(); } qlock(&tr->in.io); if(ty == Qdata){ checkstate(tr, 0, SOpen); while(tr->processed == nil) tlsrecread(tr); /* return at most what was asked for */ b = qgrab(&tr->processed, n); if(tr->debug) pprint("consumed processed %d\n", BLEN(b)); if(tr->debug) pdump(BLEN(b), b->rp, "consumed:"); qunlock(&tr->in.io); poperror(); tr->datain += BLEN(b); }else{ checkstate(tr, 1, SOpen|SHandshake|SLClose); /* * it's ok to look at state without the lock * since it only protects reading records, * and we have that tr->in.io held. */ while(!tr->opened && tr->hprocessed == nil && !qcanread(tr->handq)) tlsrecread(tr); qunlock(&tr->in.io); poperror(); if(waserror()){ qunlock(&tr->hqread); nexterror(); } qlock(&tr->hqread); if(tr->hprocessed == nil){ b = qbread(tr->handq, MaxRecLen + 1); if(*b->rp++ == RAlert){ kstrcpy(up->errstr, (char*)b->rp, ERRMAX); freeb(b); nexterror(); } tr->hprocessed = b; } b = qgrab(&tr->hprocessed, n); poperror(); qunlock(&tr->hqread); tr->handin += BLEN(b); } return b; } static long tlsread(Chan *c, void *a, long n, vlong off) { Block *volatile b; Block *nb; uchar *va; int i, ty; char *buf, *s, *e; ulong offset = off; TlsRec * tr; if(c->qid.type & QTDIR) return devdirread(c, a, n, 0, 0, tlsgen); tr = tlsdevs[CONV(c->qid)]; ty = TYPE(c->qid); switch(ty) { default: error(Ebadusefd); case Qstatus: buf = smalloc(Statlen); qlock(&tr->in.seclock); qlock(&tr->out.seclock); s = buf; e = buf + Statlen; s = seprint(s, e, "State: %s\n", tlsstate(tr->state)); s = seprint(s, e, "Version: 0x%x\n", tr->version); if(tr->in.sec != nil) s = seprint(s, e, "EncIn: %s\nHashIn: %s\n", tr->in.sec->encalg, tr->in.sec->hashalg); if(tr->in.new != nil) s = seprint(s, e, "NewEncIn: %s\nNewHashIn: %s\n", tr->in.new->encalg, tr->in.new->hashalg); if(tr->out.sec != nil) s = seprint(s, e, "EncOut: %s\nHashOut: %s\n", tr->out.sec->encalg, tr->out.sec->hashalg); if(tr->out.new != nil) seprint(s, e, "NewEncOut: %s\nNewHashOut: %s\n", tr->out.new->encalg, tr->out.new->hashalg); qunlock(&tr->in.seclock); qunlock(&tr->out.seclock); n = readstr(offset, a, n, buf); free(buf); return n; case Qstats: buf = smalloc(Statlen); s = buf; e = buf + Statlen; s = seprint(s, e, "DataIn: %lld\n", tr->datain); s = seprint(s, e, "DataOut: %lld\n", tr->dataout); s = seprint(s, e, "HandIn: %lld\n", tr->handin); seprint(s, e, "HandOut: %lld\n", tr->handout); n = readstr(offset, a, n, buf); free(buf); return n; case Qctl: buf = smalloc(Statlen); snprint(buf, Statlen, "%llud", CONV(c->qid)); n = readstr(offset, a, n, buf); free(buf); return n; case Qdata: case Qhand: b = tlsbread(c, n, offset); break; case Qencalgs: return readstr(offset, a, n, encalgs); case Qhashalgs: return readstr(offset, a, n, hashalgs); } if(waserror()){ freeblist(b); nexterror(); } n = 0; va = a; for(nb = b; nb; nb = nb->next){ i = BLEN(nb); memmove(va+n, nb->rp, i); n += i; } freeblist(b); poperror(); return n; } /* * write a block in tls records */ static void tlsrecwrite(TlsRec *tr, int type, Block *b) { Block *volatile bb; Block *nb; uchar *p, seq[8]; OneWay *volatile out; int n, maclen, pad, ok; out = &tr->out; bb = b; if(waserror()){ qunlock(&out->io); if(bb != nil) freeb(bb); nexterror(); } qlock(&out->io); if(tr->debug)pprint("send %d\n", BLEN(b)); if(tr->debug)pdump(BLEN(b), b->rp, "sent:"); ok = SHandshake|SOpen|SRClose; if(type == RAlert) ok |= SAlert; while(bb != nil){ checkstate(tr, type != RApplication, ok); /* * get at most one maximal record's input, * with padding on the front for header and * back for mac and maximal block padding. */ if(waserror()){ qunlock(&out->seclock); nexterror(); } qlock(&out->seclock); maclen = 0; pad = 0; if(out->sec != nil){ maclen = out->sec->maclen; pad = maclen + out->sec->block; } n = BLEN(bb); if(n > MaxRecLen){ n = MaxRecLen; nb = allocb(n + pad + RecHdrLen); memmove(nb->wp + RecHdrLen, bb->rp, n); bb->rp += n; }else{ /* * carefully reuse bb so it will get freed if we're out of memory */ bb = padblock(bb, RecHdrLen); if(pad) nb = padblock(bb, -pad); else nb = bb; bb = nil; } p = nb->rp; p[0] = type; put16(p+1, tr->version); put16(p+3, n); if(out->sec != nil){ put64(seq, out->seq); out->seq++; (*tr->packMac)(out->sec, out->sec->mackey, seq, p, p + RecHdrLen, n, p + RecHdrLen + n); n += maclen; /* encrypt */ n = (*out->sec->enc)(out->sec, p + RecHdrLen, n); nb->wp = p + RecHdrLen + n; /* update length */ put16(p+3, n); } if(type == RChangeCipherSpec){ if(out->new == nil) error("change cipher without a new cipher"); freeSec(out->sec); out->sec = out->new; out->new = nil; out->seq = 0; } qunlock(&out->seclock); poperror(); /* * if bwrite error's, we assume the block is queued. * if not, we're out of sync with the receiver and will not recover. */ if(waserror()){ if(strcmp(up->errstr, "interrupted") != 0) tlsError(tr, "channel error"); nexterror(); } devtab[tr->c->type]->bwrite(tr->c, nb, 0); poperror(); } qunlock(&out->io); poperror(); } static long tlsbwrite(Chan *c, Block *b, ulong offset) { int ty; ulong n; TlsRec *tr; n = BLEN(b); tr = tlsdevs[CONV(c->qid)]; if(tr == nil) panic("tlsbread"); ty = TYPE(c->qid); switch(ty) { default: return devbwrite(c, b, offset); case Qhand: tlsrecwrite(tr, RHandshake, b); tr->handout += n; break; case Qdata: checkstate(tr, 0, SOpen); tlsrecwrite(tr, RApplication, b); tr->dataout += n; break; } return n; } typedef struct Hashalg Hashalg; struct Hashalg { char *name; int maclen; void (*initkey)(Hashalg *, int, Secret *, uchar*); }; static void initmd5key(Hashalg *ha, int version, Secret *s, uchar *p) { s->maclen = ha->maclen; if(version == SSL3Version) s->mac = sslmac_md5; else s->mac = hmac_md5; memmove(s->mackey, p, ha->maclen); } static void initclearmac(Hashalg *unused1, int unused2, Secret *s, uchar *unused3) { s->maclen = 0; s->mac = nomac; } static void initsha1key(Hashalg *ha, int version, Secret *s, uchar *p) { s->maclen = ha->maclen; if(version == SSL3Version) s->mac = sslmac_sha1; else s->mac = hmac_sha1; memmove(s->mackey, p, ha->maclen); } static Hashalg hashtab[] = { { "clear", 0, initclearmac, }, { "md5", MD5dlen, initmd5key, }, { "sha1", SHA1dlen, initsha1key, }, { 0 } }; static Hashalg* parsehashalg(char *p) { Hashalg *ha; for(ha = hashtab; ha->name; ha++) if(strcmp(p, ha->name) == 0) return ha; error("unsupported hash algorithm"); return nil; } typedef struct Encalg Encalg; struct Encalg { char *name; int keylen; int ivlen; void (*initkey)(Encalg *ea, Secret *, uchar*, uchar*); }; static void initRC4key(Encalg *ea, Secret *s, uchar *p, uchar *unused1) { s->enckey = smalloc(sizeof(RC4state)); s->enc = rc4enc; s->dec = rc4enc; s->block = 0; setupRC4state(s->enckey, p, ea->keylen); } static void initDES3key(Encalg *unused1, Secret *s, uchar *p, uchar *iv) { s->enckey = smalloc(sizeof(DES3state)); s->enc = des3enc; s->dec = des3dec; s->block = 8; setupDES3state(s->enckey, (uchar(*)[8])p, iv); } static void initclearenc(Encalg *unused1, Secret *s, uchar *unused2, uchar *unused3) { s->enc = noenc; s->dec = noenc; s->block = 0; } static Encalg encrypttab[] = { { "clear", 0, 0, initclearenc }, { "rc4_128", 128/8, 0, initRC4key }, { "3des_ede_cbc", 3 * 8, 8, initDES3key }, { 0 } }; static Encalg* parseencalg(char *p) { Encalg *ea; for(ea = encrypttab; ea->name; ea++) if(strcmp(p, ea->name) == 0) return ea; error("unsupported encryption algorithm"); return nil; } static long tlswrite(Chan *c, void *a, long n, vlong off) { Encalg *ea; Hashalg *ha; TlsRec *volatile tr; Secret *volatile tos, *volatile toc; Block *volatile b; Cmdbuf *volatile cb; int m, ty; char *p, *e; uchar *volatile x; ulong offset = off; tr = tlsdevs[CONV(c->qid)]; if(tr == nil) panic("tlswrite"); ty = TYPE(c->qid); switch(ty){ case Qdata: case Qhand: p = a; e = p + n; do{ m = e - p; if(m > MaxRecLen) m = MaxRecLen; b = allocb(m); if(waserror()){ freeb(b); nexterror(); } memmove(b->wp, p, m); poperror(); b->wp += m; tlsbwrite(c, b, offset); p += m; }while(p < e); return n; case Qctl: break; default: error(Ebadusefd); return -1; } cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); } if(cb->nf < 1) error("short control request"); /* mutex with operations using what we're about to change */ if(waserror()){ qunlock(&tr->in.seclock); qunlock(&tr->out.seclock); nexterror(); } qlock(&tr->in.seclock); qlock(&tr->out.seclock); if(strcmp(cb->f[0], "fd") == 0){ if(cb->nf != 3) error("usage: fd open-fd version"); if(tr->c != nil) error(Einuse); m = strtol(cb->f[2], nil, 0); if(m < MinProtoVersion || m > MaxProtoVersion) error("unsupported version"); tr->c = buftochan(cb->f[1]); tr->version = m; tlsSetState(tr, SHandshake, SClosed); }else if(strcmp(cb->f[0], "version") == 0){ if(cb->nf != 2) error("usage: version vers"); if(tr->c == nil) error("must set fd before version"); if(tr->verset) error("version already set"); m = strtol(cb->f[1], nil, 0); if(m == SSL3Version) tr->packMac = sslPackMac; else if(m == TLSVersion) tr->packMac = tlsPackMac; else error("unsupported version"); tr->verset = 1; tr->version = m; }else if(strcmp(cb->f[0], "secret") == 0){ if(cb->nf != 5) error("usage: secret hashalg encalg isclient secretdata"); if(tr->c == nil || !tr->verset) error("must set fd and version before secrets"); if(tr->in.new != nil){ freeSec(tr->in.new); tr->in.new = nil; } if(tr->out.new != nil){ freeSec(tr->out.new); tr->out.new = nil; } ha = parsehashalg(cb->f[1]); ea = parseencalg(cb->f[2]); p = cb->f[4]; m = (strlen(p)*3)/2; x = smalloc(m); tos = nil; toc = nil; if(waserror()){ freeSec(tos); freeSec(toc); free(x); nexterror(); } m = dec64(x, m, p, strlen(p)); if(m < 2 * ha->maclen + 2 * ea->keylen + 2 * ea->ivlen) error("not enough secret data provided"); tos = smalloc(sizeof(Secret)); toc = smalloc(sizeof(Secret)); if(!ha->initkey || !ea->initkey) error("misimplemented secret algorithm"); (*ha->initkey)(ha, tr->version, tos, &x[0]); (*ha->initkey)(ha, tr->version, toc, &x[ha->maclen]); (*ea->initkey)(ea, tos, &x[2 * ha->maclen], &x[2 * ha->maclen + 2 * ea->keylen]); (*ea->initkey)(ea, toc, &x[2 * ha->maclen + ea->keylen], &x[2 * ha->maclen + 2 * ea->keylen + ea->ivlen]); if(!tos->mac || !tos->enc || !tos->dec || !toc->mac || !toc->enc || !toc->dec) error("missing algorithm implementations"); if(strtol(cb->f[3], nil, 0) == 0){ tr->in.new = tos; tr->out.new = toc; }else{ tr->in.new = toc; tr->out.new = tos; } if(tr->version == SSL3Version){ toc->unpad = sslunpad; tos->unpad = sslunpad; }else{ toc->unpad = tlsunpad; tos->unpad = tlsunpad; } toc->encalg = ea->name; toc->hashalg = ha->name; tos->encalg = ea->name; tos->hashalg = ha->name; free(x); poperror(); }else if(strcmp(cb->f[0], "changecipher") == 0){ if(cb->nf != 1) error("usage: changecipher"); if(tr->out.new == nil) error("cannot change cipher spec without setting secret"); qunlock(&tr->in.seclock); qunlock(&tr->out.seclock); poperror(); free(cb); poperror(); /* * the real work is done as the message is written * so the stream is encrypted in sync. */ b = allocb(1); *b->wp++ = 1; tlsrecwrite(tr, RChangeCipherSpec, b); return n; }else if(strcmp(cb->f[0], "opened") == 0){ if(cb->nf != 1) error("usage: opened"); if(tr->in.sec == nil || tr->out.sec == nil) error("cipher must be configured before enabling data messages"); lock(&tr->statelk); if(tr->state != SHandshake && tr->state != SOpen){ unlock(&tr->statelk); error("cannot enable data messages"); } tr->state = SOpen; unlock(&tr->statelk); tr->opened = 1; }else if(strcmp(cb->f[0], "alert") == 0){ if(cb->nf != 2) error("usage: alert n"); if(tr->c == nil) error("must set fd before sending alerts"); m = strtol(cb->f[1], nil, 0); qunlock(&tr->in.seclock); qunlock(&tr->out.seclock); poperror(); free(cb); poperror(); sendAlert(tr, m); if(m == ECloseNotify) tlsclosed(tr, SLClose); return n; } else if(strcmp(cb->f[0], "debug") == 0){ if(cb->nf == 2){ if(strcmp(cb->f[1], "on") == 0) tr->debug = 1; else tr->debug = 0; } else tr->debug = 1; } else error(Ebadarg); qunlock(&tr->in.seclock); qunlock(&tr->out.seclock); poperror(); free(cb); poperror(); return n; } static void tlsinit(void) { struct Encalg *e; struct Hashalg *h; int n; char *cp; static int already; if(!already){ fmtinstall('H', encodefmt); already = 1; } tlsdevs = smalloc(sizeof(TlsRec*) * maxtlsdevs); trnames = smalloc((sizeof *trnames) * maxtlsdevs); n = 1; for(e = encrypttab; e->name != nil; e++) n += strlen(e->name) + 1; cp = encalgs = smalloc(n); for(e = encrypttab;;){ strcpy(cp, e->name); cp += strlen(e->name); e++; if(e->name == nil) break; *cp++ = ' '; } *cp = 0; n = 1; for(h = hashtab; h->name != nil; h++) n += strlen(h->name) + 1; cp = hashalgs = smalloc(n); for(h = hashtab;;){ strcpy(cp, h->name); cp += strlen(h->name); h++; if(h->name == nil) break; *cp++ = ' '; } *cp = 0; } Dev tlsdevtab = { 'a', "tls", devreset, tlsinit, devshutdown, tlsattach, tlswalk, tlsstat, tlsopen, devcreate, tlsclose, tlsread, tlsbread, tlswrite, tlsbwrite, devremove, tlswstat, }; /* get channel associated with an fd */ static Chan* buftochan(char *p) { Chan *c; int fd; if(p == 0) error(Ebadarg); fd = strtoul(p, 0, 0); if(fd < 0) error(Ebadarg); c = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ return c; } static void sendAlert(TlsRec *tr, int err) { Block *b; int i, fatal; char *msg; if(tr->debug)pprint("sendAlert %d\n", err); fatal = 1; msg = "tls unknown alert"; for(i=0; i < nelem(tlserrs); i++) { if(tlserrs[i].err == err) { msg = tlserrs[i].msg; if(tr->version == SSL3Version) err = tlserrs[i].sslerr; else err = tlserrs[i].tlserr; fatal = tlserrs[i].fatal; break; } } if(!waserror()){ b = allocb(2); *b->wp++ = fatal + 1; *b->wp++ = err; if(fatal) tlsSetState(tr, SAlert, SOpen|SHandshake|SRClose); tlsrecwrite(tr, RAlert, b); poperror(); } if(fatal) tlsError(tr, msg); } static void tlsError(TlsRec *tr, char *msg) { int s; if(tr->debug)pprint("tleError %s\n", msg); lock(&tr->statelk); s = tr->state; tr->state = SError; if(s != SError){ strncpy(tr->err, msg, ERRMAX - 1); tr->err[ERRMAX - 1] = '\0'; } unlock(&tr->statelk); if(s != SError) alertHand(tr, msg); } static void tlsSetState(TlsRec *tr, int new, int old) { lock(&tr->statelk); if(tr->state & old) tr->state = new; unlock(&tr->statelk); } /* hand up a digest connection */ static void tlshangup(TlsRec *tr) { Block *b; qlock(&tr->in.io); for(b = tr->processed; b; b = tr->processed){ tr->processed = b->next; freeb(b); } if(tr->unprocessed != nil){ freeb(tr->unprocessed); tr->unprocessed = nil; } qunlock(&tr->in.io); tlsSetState(tr, SClosed, ~0); } static TlsRec* newtls(Chan *ch) { TlsRec **pp, **ep, **np; char **nmp; int t, newmax; if(waserror()) { unlock(&tdlock); nexterror(); } lock(&tdlock); ep = &tlsdevs[maxtlsdevs]; for(pp = tlsdevs; pp < ep; pp++) if(*pp == nil) break; if(pp >= ep) { if(maxtlsdevs >= MaxTlsDevs) { unlock(&tdlock); poperror(); return nil; } newmax = 2 * maxtlsdevs; if(newmax > MaxTlsDevs) newmax = MaxTlsDevs; np = smalloc(sizeof(TlsRec*) * newmax); memmove(np, tlsdevs, sizeof(TlsRec*) * maxtlsdevs); tlsdevs = np; pp = &tlsdevs[maxtlsdevs]; memset(pp, 0, sizeof(TlsRec*)*(newmax - maxtlsdevs)); nmp = smalloc(sizeof *nmp * newmax); memmove(nmp, trnames, sizeof *nmp * maxtlsdevs); trnames = nmp; maxtlsdevs = newmax; } *pp = mktlsrec(); if(pp - tlsdevs >= tdhiwat) tdhiwat++; t = TYPE(ch->qid); if(t == Qclonus) t = Qctl; ch->qid.path = QID(pp - tlsdevs, t); ch->qid.vers = 0; unlock(&tdlock); poperror(); return *pp; } static TlsRec * mktlsrec(void) { TlsRec *tr; tr = mallocz(sizeof(*tr), 1); if(tr == nil) error(Enomem); tr->state = SClosed; tr->ref = 1; kstrdup(&tr->user, up->user); tr->perm = 0660; return tr; } static char* tlsstate(int s) { switch(s){ case SHandshake: return "Handshaking"; case SOpen: return "Established"; case SRClose: return "RemoteClosed"; case SLClose: return "LocalClosed"; case SAlert: return "Alerting"; case SError: return "Errored"; case SClosed: return "Closed"; } return "Unknown"; } static void freeSec(Secret *s) { if(s != nil){ free(s->enckey); free(s); } } static int noenc(Secret *unused1, uchar *unused2, int n) { return n; } static int rc4enc(Secret *sec, uchar *buf, int n) { rc4(sec->enckey, buf, n); return n; } static int tlsunpad(uchar *buf, int n, int block) { int pad, nn; pad = buf[n - 1]; nn = n - 1 - pad; if(nn <= 0 || n % block) return -1; while(--n > nn) if(pad != buf[n - 1]) return -1; return nn; } static int sslunpad(uchar *buf, int n, int block) { int pad, nn; pad = buf[n - 1]; nn = n - 1 - pad; if(nn <= 0 || n % block) return -1; return nn; } static int blockpad(uchar *buf, int n, int block) { int pad, nn; nn = n + block; nn -= nn % block; pad = nn - (n + 1); while(n < nn) buf[n++] = pad; return nn; } static int des3enc(Secret *sec, uchar *buf, int n) { n = blockpad(buf, n, 8); des3CBCencrypt(buf, n, sec->enckey); return n; } static int des3dec(Secret *sec, uchar *buf, int n) { des3CBCdecrypt(buf, n, sec->enckey); return (*sec->unpad)(buf, n, 8); } static DigestState* nomac(uchar *unused1, ulong unused2, uchar *unused3, ulong unused4, uchar *unused5, DigestState *unused6) { return nil; } /* * sslmac: mac calculations for ssl 3.0 only; tls 1.0 uses the standard hmac. */ static DigestState* sslmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s, DigestState*(*x)(uchar*, ulong, uchar*, DigestState*), int xlen, int padlen) { int i; uchar pad[48], innerdigest[20]; if(xlen > sizeof(innerdigest) || padlen > sizeof(pad)) return nil; if(klen>64) return nil; /* first time through */ if(s == nil){ for(i=0; imac)(buf, 11, mackey, sec->maclen, 0, 0); (*sec->mac)(body, len, mackey, sec->maclen, mac, s); } static void tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac) { DigestState *s; uchar buf[13]; memmove(buf, seq, 8); memmove(&buf[8], header, 5); s = (*sec->mac)(buf, 13, mackey, sec->maclen, 0, 0); (*sec->mac)(body, len, mackey, sec->maclen, mac, s); } static void put32(uchar *p, u32int x) { p[0] = x>>24; p[1] = x>>16; p[2] = x>>8; p[3] = x; } static void put64(uchar *p, vlong x) { put32(p, (u32int)(x >> 32)); put32(p+4, (u32int)x); } static void put24(uchar *p, int x) { p[0] = x>>16; p[1] = x>>8; p[2] = x; } static void put16(uchar *p, int x) { p[0] = x>>8; p[1] = x; } /* static u32int get32(uchar *p) { return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]; } */ static int get16(uchar *p) { return (p[0]<<8)|p[1]; } static char *charmap = "0123456789abcdef"; static void pdump(int len, void *a, char *tag) { uchar *p; int i; char buf[65+32]; char *q; p = a; strcpy(buf, tag); while(len > 0){ q = buf + strlen(tag); for(i = 0; len > 0 && i < 32; i++){ if(*p >= ' ' && *p < 0x7f){ *q++ = ' '; *q++ = *p; } else { *q++ = charmap[*p>>4]; *q++ = charmap[*p & 0xf]; } len--; p++; } *q = 0; if(len > 0) pprint("%s...\n", buf); else pprint("%s\n", buf); } } drawterm-20170818/kern/error.c000066400000000000000000000040641314554504700160630ustar00rootroot00000000000000char Enoerror[] = "no error"; char Emount[] = "inconsistent mount"; char Eunmount[] = "not mounted"; char Eunion[] = "not in union"; char Emountrpc[] = "mount rpc error"; char Eshutdown[] = "device shut down"; char Enocreate[] = "mounted directory forbids creation"; char Enonexist[] = "file does not exist"; char Eexist[] = "file already exists"; char Ebadsharp[] = "unknown device in # filename"; char Enotdir[] = "not a directory"; char Eisdir[] = "file is a directory"; char Ebadchar[] = "bad character in file name"; char Efilename[] = "file name syntax"; char Eperm[] = "permission denied"; char Ebadusefd[] = "inappropriate use of fd"; char Ebadarg[] = "bad arg in system call"; char Einuse[] = "device or object already in use"; char Eio[] = "i/o error"; char Etoobig[] = "read or write too large"; char Etoosmall[] = "read or write too small"; char Enoport[] = "network port not available"; char Ehungup[] = "i/o on hungup channel"; char Ebadctl[] = "bad process or channel control request"; char Enodev[] = "no free devices"; char Eprocdied[] = "process exited"; char Enochild[] = "no living children"; char Eioload[] = "i/o error in demand load"; char Enovmem[] = "virtual memory allocation failed"; char Ebadfd[] = "fd out of range or not open"; char Enofd[] = "no free file descriptors"; char Eisstream[] = "seek on a stream"; char Ebadexec[] = "exec header invalid"; char Etimedout[] = "connection timed out"; char Econrefused[] = "connection refused"; char Econinuse[] = "connection in use"; char Eintr[] = "interrupted"; char Enomem[] = "kernel allocate failed"; char Enoswap[] = "swap space full"; char Esoverlap[] = "segments overlap"; char Emouseset[] = "mouse type already set"; char Eshort[] = "i/o count too small"; char Egreg[] = "ken has left the building"; char Ebadspec[] = "bad attach specifier"; char Enoreg[] = "process has no saved registers"; char Enoattach[] = "mount/attach disallowed"; char Eshortstat[] = "stat buffer too small"; char Ebadstat[] = "malformed stat buffer"; char Enegoff[] = "negative i/o offset"; char Ecmdargs[] = "wrong #args in control message"; drawterm-20170818/kern/error.h000066400000000000000000000050271314554504700160700ustar00rootroot00000000000000extern char Enoerror[]; /* no error */ extern char Emount[]; /* inconsistent mount */ extern char Eunmount[]; /* not mounted */ extern char Eunion[]; /* not in union */ extern char Emountrpc[]; /* mount rpc error */ extern char Eshutdown[]; /* device shut down */ extern char Enocreate[]; /* mounted directory forbids creation */ extern char Enonexist[]; /* file does not exist */ extern char Eexist[]; /* file already exists */ extern char Ebadsharp[]; /* unknown device in # filename */ extern char Enotdir[]; /* not a directory */ extern char Eisdir[]; /* file is a directory */ extern char Ebadchar[]; /* bad character in file name */ extern char Efilename[]; /* file name syntax */ extern char Eperm[]; /* permission denied */ extern char Ebadusefd[]; /* inappropriate use of fd */ extern char Ebadarg[]; /* bad arg in system call */ extern char Einuse[]; /* device or object already in use */ extern char Eio[]; /* i/o error */ extern char Etoobig[]; /* read or write too large */ extern char Etoosmall[]; /* read or write too small */ extern char Enoport[]; /* network port not available */ extern char Ehungup[]; /* i/o on hungup channel */ extern char Ebadctl[]; /* bad process or channel control request */ extern char Enodev[]; /* no free devices */ extern char Eprocdied[]; /* process exited */ extern char Enochild[]; /* no living children */ extern char Eioload[]; /* i/o error in demand load */ extern char Enovmem[]; /* virtual memory allocation failed */ extern char Ebadfd[]; /* fd out of range or not open */ extern char Enofd[]; /* no free file descriptors */ extern char Eisstream[]; /* seek on a stream */ extern char Ebadexec[]; /* exec header invalid */ extern char Etimedout[]; /* connection timed out */ extern char Econrefused[]; /* connection refused */ extern char Econinuse[]; /* connection in use */ extern char Eintr[]; /* interrupted */ extern char Enomem[]; /* kernel allocate failed */ extern char Enoswap[]; /* swap space full */ extern char Esoverlap[]; /* segments overlap */ extern char Emouseset[]; /* mouse type already set */ extern char Eshort[]; /* i/o count too small */ extern char Egreg[]; /* ken has left the building */ extern char Ebadspec[]; /* bad attach specifier */ extern char Enoreg[]; /* process has no saved registers */ extern char Enoattach[]; /* mount/attach disallowed */ extern char Eshortstat[]; /* stat buffer too small */ extern char Ebadstat[]; /* malformed stat buffer */ extern char Enegoff[]; /* negative i/o offset */ extern char Ecmdargs[]; /* wrong #args in control message */ drawterm-20170818/kern/exportfs.c000066400000000000000000000322041314554504700166010ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" typedef struct Fid Fid; typedef struct Export Export; typedef struct Exq Exq; #define nil ((void*)0) enum { Nfidhash = 1, MAXRPC = MAXMSG+MAXFDATA, MAXDIRREAD = (MAXFDATA/DIRLEN)*DIRLEN }; struct Export { Ref r; Exq* work; Lock fidlock; Fid* fid[Nfidhash]; Chan* root; Chan* io; Pgrp* pgrp; int npart; char part[MAXRPC]; }; struct Fid { Fid* next; Fid** last; Chan* chan; long offset; int fid; int ref; /* fcalls using the fid; locked by Export.Lock */ int attached; /* fid attached or cloned but not clunked */ }; struct Exq { Lock lk; int nointr; int noresponse; /* don't respond to this one */ Exq* next; int shut; /* has been noted for shutdown */ Export* export; void* slave; Fcall rpc; char buf[MAXRPC]; }; struct { Lock l; Qlock qwait; Rendez rwait; Exq *head; /* work waiting for a slave */ Exq *tail; }exq; static void exshutdown(Export*); static void exflush(Export*, int, int); static void exslave(void*); static void exfree(Export*); static void exportproc(Export*); static char* Exauth(Export*, Fcall*); static char* Exattach(Export*, Fcall*); static char* Exclunk(Export*, Fcall*); static char* Excreate(Export*, Fcall*); static char* Exopen(Export*, Fcall*); static char* Exread(Export*, Fcall*); static char* Exremove(Export*, Fcall*); static char* Exstat(Export*, Fcall*); static char* Exwalk(Export*, Fcall*); static char* Exwrite(Export*, Fcall*); static char* Exwstat(Export*, Fcall*); static char* Exversion(Export*, Fcall*); static char *(*fcalls[Tmax])(Export*, Fcall*); static char Enofid[] = "no such fid"; static char Eseekdir[] = "can't seek on a directory"; static char Ereaddir[] = "unaligned read of a directory"; static int exdebug = 0; int sysexport(int fd) { Chan *c; Export *fs; if(waserror()) return -1; c = fdtochan(fd, ORDWR, 1, 1); poperror(); c->flag |= CMSG; fs = mallocz(sizeof(Export)); fs->r.ref = 1; fs->pgrp = up->pgrp; refinc(&fs->pgrp->r); refinc(&up->slash->r); fs->root = up->slash; refinc(&fs->root->r); fs->root = domount(fs->root); fs->io = c; exportproc(fs); return 0; } static void exportinit(void) { lock(&exq.l); if(fcalls[Tversion] != nil) { unlock(&exq.l); return; } fmtinstall('F', fcallfmt); fmtinstall('D', dirfmt); fmtinstall('M', dirmodefmt); fcalls[Tversion] = Exversion; fcalls[Tauth] = Exauth; fcalls[Tattach] = Exattach; fcalls[Twalk] = Exwalk; fcalls[Topen] = Exopen; fcalls[Tcreate] = Excreate; fcalls[Tread] = Exread; fcalls[Twrite] = Exwrite; fcalls[Tclunk] = Exclunk; fcalls[Tremove] = Exremove; fcalls[Tstat] = Exstat; fcalls[Twstat] = Exwstat; unlock(&exq.l); } void exportproc(Export *fs) { Exq *q; char *buf; int n, cn, len; exportinit(); for(;;){ q = mallocz(sizeof(Exq)); if(q == 0) panic("no memory"); q->rpc.data = q->buf + MAXMSG; buf = q->buf; len = MAXRPC; if(fs->npart) { memmove(buf, fs->part, fs->npart); buf += fs->npart; len -= fs->npart; goto chk; } for(;;) { if(waserror()) goto bad; n = (*devtab[fs->io->type].read)(fs->io, buf, len, 0); poperror(); if(n <= 0) goto bad; buf += n; len -= n; chk: n = buf - q->buf; /* convM2S returns size of correctly decoded message */ cn = convM2S(q->buf, &q->rpc, n); if(cn < 0){ iprint("bad message type in devmnt\n"); goto bad; } if(cn > 0) { n -= cn; if(n < 0){ iprint("negative size in devmnt"); goto bad; } fs->npart = n; if(n != 0) memmove(fs->part, q->buf+cn, n); break; } } if(exdebug) iprint("export %d <- %F\n", getpid(), &q->rpc); if(q->rpc.type == Tflush){ exflush(fs, q->rpc.tag, q->rpc.oldtag); free(q); continue; } q->export = fs; refinc(&fs->r); lock(&exq.l); if(exq.head == nil) exq.head = q; else exq.tail->next = q; q->next = nil; exq.tail = q; unlock(&exq.l); if(exq.qwait.first == nil) { n = thread("exportfs", exslave, nil); /* iprint("launch export (pid=%ux)\n", n); */ } rendwakeup(&exq.rwait); } bad: free(q); exshutdown(fs); exfree(fs); } void exflush(Export *fs, int flushtag, int tag) { Exq *q, **last; int n; Fcall fc; char buf[MAXMSG]; /* hasn't been started? */ lock(&exq.l); last = &exq.head; for(q = exq.head; q != nil; q = q->next){ if(q->export == fs && q->rpc.tag == tag){ *last = q->next; unlock(&exq.l); exfree(fs); free(q); goto Respond; } last = &q->next; } unlock(&exq.l); /* in progress? */ lock(&fs->r.l); for(q = fs->work; q != nil; q = q->next){ if(q->rpc.tag == tag && !q->noresponse){ lock(&q->lk); q->noresponse = 1; if(!q->nointr) intr(q->slave); unlock(&q->lk); unlock(&fs->r.l); goto Respond; return; } } unlock(&fs->r.l); if(exdebug) iprint("exflush: did not find rpc: %d\n", tag); Respond: fc.type = Rflush; fc.tag = flushtag; n = convS2M(&fc, buf); if(exdebug) iprint("exflush -> %F\n", &fc); if(!waserror()){ (*devtab[fs->io->type].write)(fs->io, buf, n, 0); poperror(); } } void exshutdown(Export *fs) { Exq *q, **last; lock(&exq.l); last = &exq.head; for(q = exq.head; q != nil; q = *last){ if(q->export == fs){ *last = q->next; exfree(fs); free(q); continue; } last = &q->next; } unlock(&exq.l); lock(&fs->r.l); q = fs->work; while(q != nil){ if(q->shut){ q = q->next; continue; } q->shut = 1; unlock(&fs->r.l); /* postnote(q->slave, 1, "interrupted", NUser); */ iprint("postnote 2!\n"); lock(&fs->r.l); q = fs->work; } unlock(&fs->r.l); } void exfree(Export *fs) { Fid *f, *n; int i; if(refdec(&fs->r) != 0) return; closepgrp(fs->pgrp); cclose(fs->root); cclose(fs->io); for(i = 0; i < Nfidhash; i++){ for(f = fs->fid[i]; f != nil; f = n){ if(f->chan != nil) cclose(f->chan); n = f->next; free(f); } } free(fs); } int exwork(void *a) { return exq.head != nil; } void exslave(void *a) { Export *fs; Exq *q, *t, **last; char *err; int n; /* closepgrp(up->pgrp); up->pgrp = nil; */ for(;;){ qlock(&exq.qwait); rendsleep(&exq.rwait, exwork, nil); lock(&exq.l); q = exq.head; if(q == nil) { unlock(&exq.l); qunlock(&exq.qwait); continue; } exq.head = q->next; q->slave = curthread(); unlock(&exq.l); qunlock(&exq.qwait); q->noresponse = 0; q->nointr = 0; fs = q->export; lock(&fs->r.l); q->next = fs->work; fs->work = q; unlock(&fs->r.l); up->pgrp = q->export->pgrp; if(exdebug > 1) iprint("exslave dispatch %d %F\n", getpid(), &q->rpc); if(waserror()){ iprint("exslave err %r\n"); err = up->errstr; goto Err; } if(q->rpc.type >= Tmax || !fcalls[q->rpc.type]) err = "bad fcall type"; else err = (*fcalls[q->rpc.type])(fs, &q->rpc); poperror(); Err:; q->rpc.type++; if(err){ q->rpc.type = Rerror; strncpy(q->rpc.ename, err, ERRLEN); } n = convS2M(&q->rpc, q->buf); if(exdebug) iprint("exslve %d -> %F\n", getpid(), &q->rpc); lock(&q->lk); if(q->noresponse == 0){ q->nointr = 1; clearintr(); if(!waserror()){ (*devtab[fs->io->type].write)(fs->io, q->buf, n, 0); poperror(); } } unlock(&q->lk); /* * exflush might set noresponse at this point, but * setting noresponse means don't send a response now; * it's okay that we sent a response already. */ if(exdebug > 1) iprint("exslave %d written %d\n", getpid(), q->rpc.tag); lock(&fs->r.l); last = &fs->work; for(t = fs->work; t != nil; t = t->next){ if(t == q){ *last = q->next; break; } last = &t->next; } unlock(&fs->r.l); exfree(q->export); free(q); } iprint("exslave shut down"); threadexit(); } Fid* Exmkfid(Export *fs, int fid) { ulong h; Fid *f, *nf; nf = mallocz(sizeof(Fid)); if(nf == nil) return nil; lock(&fs->fidlock); h = fid % Nfidhash; for(f = fs->fid[h]; f != nil; f = f->next){ if(f->fid == fid){ unlock(&fs->fidlock); free(nf); return nil; } } nf->next = fs->fid[h]; if(nf->next != nil) nf->next->last = &nf->next; nf->last = &fs->fid[h]; fs->fid[h] = nf; nf->fid = fid; nf->ref = 1; nf->attached = 1; nf->offset = 0; nf->chan = nil; unlock(&fs->fidlock); return nf; } Fid* Exgetfid(Export *fs, int fid) { Fid *f; ulong h; lock(&fs->fidlock); h = fid % Nfidhash; for(f = fs->fid[h]; f; f = f->next) { if(f->fid == fid){ if(f->attached == 0) break; f->ref++; unlock(&fs->fidlock); return f; } } unlock(&fs->fidlock); return nil; } void Exputfid(Export *fs, Fid *f) { lock(&fs->fidlock); f->ref--; if(f->ref == 0 && f->attached == 0){ if(f->chan != nil) cclose(f->chan); f->chan = nil; *f->last = f->next; if(f->next != nil) f->next->last = f->last; unlock(&fs->fidlock); free(f); return; } unlock(&fs->fidlock); } char* Exsession(Export *e, Fcall *rpc) { memset(rpc->authid, 0, sizeof(rpc->authid)); memset(rpc->authdom, 0, sizeof(rpc->authdom)); memset(rpc->chal, 0, sizeof(rpc->chal)); return nil; } char* Exauth(Export *e, Fcall *f) { return "authentication not required"; } char* Exattach(Export *fs, Fcall *rpc) { Fid *f; f = Exmkfid(fs, rpc->fid); if(f == nil) return Einuse; if(waserror()){ f->attached = 0; Exputfid(fs, f); return up->errstr; } f->chan = clone(fs->root, nil); poperror(); rpc->qid = f->chan->qid; Exputfid(fs, f); return nil; } char* Exclone(Export *fs, Fcall *rpc) { Fid *f, *nf; if(rpc->fid == rpc->newfid) return Einuse; f = Exgetfid(fs, rpc->fid); if(f == nil) return Enofid; nf = Exmkfid(fs, rpc->newfid); if(nf == nil){ Exputfid(fs, f); return Einuse; } if(waserror()){ Exputfid(fs, f); Exputfid(fs, nf); return up->errstr; } nf->chan = clone(f->chan, nil); poperror(); Exputfid(fs, f); Exputfid(fs, nf); return nil; } char* Exclunk(Export *fs, Fcall *rpc) { Fid *f; f = Exgetfid(fs, rpc->fid); if(f != nil){ f->attached = 0; Exputfid(fs, f); } return nil; } char* Exwalk(Export *fs, Fcall *rpc) { Fid *f; Chan *c; f = Exgetfid(fs, rpc->fid); if(f == nil) return Enofid; if(waserror()){ Exputfid(fs, f); return up->errstr; } c = walk(f->chan, rpc->name, 1); if(c == nil) error(Enonexist); poperror(); f->chan = c; rpc->qid = c->qid; Exputfid(fs, f); return nil; } char* Exopen(Export *fs, Fcall *rpc) { Fid *f; Chan *c; f = Exgetfid(fs, rpc->fid); if(f == nil) return Enofid; if(waserror()){ Exputfid(fs, f); return up->errstr; } c = f->chan; c = (*devtab[c->type].open)(c, rpc->mode); poperror(); f->chan = c; f->offset = 0; rpc->qid = f->chan->qid; Exputfid(fs, f); return nil; } char* Excreate(Export *fs, Fcall *rpc) { Fid *f; Chan *c; f = Exgetfid(fs, rpc->fid); if(f == nil) return Enofid; if(waserror()){ Exputfid(fs, f); return up->errstr; } c = f->chan; if(c->mnt && !(c->flag&CCREATE)) c = createdir(c); (*devtab[c->type].create)(c, rpc->name, rpc->mode, rpc->perm); poperror(); f->chan = c; rpc->qid = f->chan->qid; Exputfid(fs, f); return nil; } char* Exread(Export *fs, Fcall *rpc) { Fid *f; Chan *c; long off; int dir, n, seek; f = Exgetfid(fs, rpc->fid); if(f == nil) return Enofid; c = f->chan; dir = c->qid.path & CHDIR; if(dir){ rpc->count -= rpc->count%DIRLEN; if(rpc->offset%DIRLEN || rpc->count==0){ Exputfid(fs, f); return Ereaddir; } if(f->offset > rpc->offset){ Exputfid(fs, f); return Eseekdir; } } if(waserror()) { Exputfid(fs, f); return up->errstr; } for(;;){ n = rpc->count; seek = 0; off = rpc->offset; if(dir && f->offset != off){ off = f->offset; n = rpc->offset - off; if(n > MAXDIRREAD) n = MAXDIRREAD; seek = 1; } if(dir && c->mnt != nil) n = unionread(c, rpc->data, n); else{ c->offset = off; n = (*devtab[c->type].read)(c, rpc->data, n, off); } if(n == 0 || !seek) break; f->offset = off + n; c->offset += n; } rpc->count = n; poperror(); Exputfid(fs, f); return nil; } char* Exwrite(Export *fs, Fcall *rpc) { Fid *f; Chan *c; f = Exgetfid(fs, rpc->fid); if(f == nil) return Enofid; if(waserror()){ Exputfid(fs, f); return up->errstr; } c = f->chan; if(c->qid.path & CHDIR) error(Eisdir); rpc->count = (*devtab[c->type].write)(c, rpc->data, rpc->count, rpc->offset); poperror(); Exputfid(fs, f); return nil; } char* Exstat(Export *fs, Fcall *rpc) { Fid *f; Chan *c; f = Exgetfid(fs, rpc->fid); if(f == nil) return Enofid; if(waserror()){ Exputfid(fs, f); return up->errstr; } c = f->chan; (*devtab[c->type].stat)(c, rpc->stat); poperror(); Exputfid(fs, f); return nil; } char* Exwstat(Export *fs, Fcall *rpc) { Fid *f; Chan *c; f = Exgetfid(fs, rpc->fid); if(f == nil) return Enofid; if(waserror()){ Exputfid(fs, f); return up->errstr; } c = f->chan; (*devtab[c->type].wstat)(c, rpc->stat); poperror(); Exputfid(fs, f); return nil; } char* Exremove(Export *fs, Fcall *rpc) { Fid *f; Chan *c; f = Exgetfid(fs, rpc->fid); if(f == nil) return Enofid; if(waserror()){ Exputfid(fs, f); return up->errstr; } c = f->chan; (*devtab[c->type].remove)(c); poperror(); /* * chan is already clunked by remove. * however, we need to recover the chan, * and follow sysremove's lead in making to point to root. */ c->type = 0; f->attached = 0; Exputfid(fs, f); return nil; } drawterm-20170818/kern/fns.h000066400000000000000000000245661314554504700155360ustar00rootroot00000000000000#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1)) void accounttime(void); void addclock0link(void (*)(void), int); int addphysseg(Physseg*); void addbootfile(char*, uchar*, ulong); Block* adjustblock(Block*, int); void alarmkproc(void*); Block* allocb(int); int anyhigher(void); int anyready(void); Page* auxpage(void); Block* bl2mem(uchar*, Block*, int); int blocklen(Block*); void callwithureg(void(*)(Ureg*)); char* c2name(Chan*); int cangetc(void*); int canlock(Lock*); int canpage(Proc*); int canputc(void*); int canqlock(QLock*); int canrlock(RWlock*); void chandevinit(void); void chandevreset(void); void chandevshutdown(void); void chanfree(Chan*); void chanrec(Mnt*); void checkalarms(void); void checkb(Block*, char*); void cinit(void); Chan* cclone(Chan*); void cclose(Chan*); char* clipread(void); int clipwrite(char*); void closeegrp(Egrp*); void closefgrp(Fgrp*); void closemount(Mount*); void closepgrp(Pgrp*); void closergrp(Rgrp*); long clrfpintr(void); void cmderror(Cmdbuf*, char*); int cmount(Chan**, Chan*, int, char*); void cnameclose(Cname*); void confinit(void); void confinit1(int); int consactive(void); extern void (*consdebug)(void); void copen(Chan*); Block* concatblock(Block*); Block* copyblock(Block*, int); void copypage(Page*, Page*); int cread(Chan*, uchar*, int, vlong); void cunmount(Chan*, Chan*); void cupdate(Chan*, uchar*, int, vlong); void cwrite(Chan*, uchar*, int, vlong); ulong dbgpc(Proc*); int decref(Ref*); int decrypt(void*, void*, int); void delay(int); Chan* devattach(int, char*); Block* devbread(Chan*, long, ulong); long devbwrite(Chan*, Block*, ulong); Chan* devclone(Chan*); int devconfig(int, char *, DevConf *); void devcreate(Chan*, char*, int, ulong); void devdir(Chan*, Qid, char*, vlong, char*, long, Dir*); long devdirread(Chan*, char*, long, Dirtab*, int, Devgen*); Devgen devgen; void devinit(void); int devno(int, int); Chan* devopen(Chan*, int, Dirtab*, int, Devgen*); void devpermcheck(char*, ulong, int); void devpower(int); void devremove(Chan*); void devreset(void); void devshutdown(void); int devstat(Chan*, uchar*, int, Dirtab*, int, Devgen*); Walkqid* devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*); int devwstat(Chan*, uchar*, int); void drawactive(int); void drawcmap(void); int drawcanqlock(void); void drawqlock(void); void drawqunlock(void); void dumpaproc(Proc*); void dumpqueues(void); void dumpregs(Ureg*); void dumpstack(void); Fgrp* dupfgrp(Fgrp*); void duppage(Page*); void dupswap(Page*); int emptystr(char*); int encrypt(void*, void*, int); void envcpy(Egrp*, Egrp*); int eqchan(Chan*, Chan*, int); int eqqid(Qid, Qid); void error(char*); long execregs(ulong, ulong, ulong); void exhausted(char*); void exit(int); uvlong fastticks(uvlong*); int fault(ulong, int); void fdclose(int, int); Chan* fdtochan(int, int, int, int); int fixfault(Segment*, ulong, int, int); void flushmmu(void); void forkchild(Proc*, Ureg*); void forkret(void); void free(void*); void freeb(Block*); void freeblist(Block*); int freebroken(void); void freepte(Segment*, Pte*); void freesegs(int); void freesession(Session*); ulong getmalloctag(void*); ulong getrealloctag(void*); void gotolabel(Label*); char* getconfenv(void); int haswaitq(void*); long hostdomainwrite(char*, int); long hostownerwrite(char*, int); void hzsched(void); void iallocinit(void); Block* iallocb(int); void iallocsummary(void); long ibrk(ulong, int); void ilock(Lock*); void iunlock(Lock*); int incref(Ref*); void initseg(void); int iprint(char*, ...); void isdir(Chan*); int iseve(void); #define islo() (0) Segment* isoverlap(Proc*, ulong, int); int ispages(void*); int isphysseg(char*); void ixsummary(void); void kbdclock(void); int kbdcr2nl(Queue*, int); int kbdputc(Queue*, int); void kbdrepeat(int); long keyread(char*, int, long); void kickpager(void); void killbig(void); int kproc(char*, void(*)(void*), void*); void kprocchild(Proc*, void (*)(void*), void*); extern void (*kproftimer)(ulong); void ksetenv(char*, char*, int); void kstrcpy(char*, char*, int); void kstrdup(char**, char*); long latin1(Rune*, int); void lock(Lock*); void lockinit(void); void logopen(Log*); void logclose(Log*); char* logctl(Log*, int, char**, Logflag*); void logn(Log*, int, void*, int); long logread(Log*, void*, ulong, long); void log(Log*, int, char*, ...); Cmdtab* lookupcmd(Cmdbuf*, Cmdtab*, int); void machinit(void); void* mallocz(ulong, int); #define malloc kmalloc void* malloc(ulong); void mallocsummary(void); Block* mem2bl(uchar*, int); void mfreeseg(Segment*, ulong, int); void microdelay(int); void mkqid(Qid*, vlong, ulong, int); void mmurelease(Proc*); void mmuswitch(Proc*); Chan* mntauth(Chan*, char*); void mntdump(void); long mntversion(Chan*, char*, int, int); void mountfree(Mount*); ulong ms2tk(ulong); ulong msize(void*); ulong ms2tk(ulong); uvlong ms2fastticks(ulong); void muxclose(Mnt*); Chan* namec(char*, int, int, ulong); Chan* newchan(void); int newfd(Chan*); Mhead* newmhead(Chan*); Mount* newmount(Mhead*, Chan*, int, char*); Page* newpage(int, Segment **, ulong); Pgrp* newpgrp(void); Rgrp* newrgrp(void); Proc* newproc(void); char* nextelem(char*, char*); void nexterror(void); Cname* newcname(char*); int notify(Ureg*); int nrand(int); int okaddr(ulong, ulong, int); int openmode(ulong); void oserrstr(void); void oserror(void); Block* packblock(Block*); Block* padblock(Block*, int); void pagechainhead(Page*); void pageinit(void); void pagersummary(void); void panic(char*, ...); Cmdbuf* parsecmd(char *a, int n); ulong perfticks(void); void pexit(char*, int); int preempted(void); void printinit(void); int procindex(ulong); void pgrpcpy(Pgrp*, Pgrp*); void pgrpnote(ulong, char*, long, int); Pgrp* pgrptab(int); void pio(Segment *, ulong, ulong, Page **); #define poperror() up->nerrlab-- void portclock(Ureg*); int postnote(Proc*, int, char*, int); int pprint(char*, ...); void prflush(void); ulong procalarm(ulong); int proccounter(char *name); void procctl(Proc*); void procdump(void); int procfdprint(Chan*, int, int, char*, int); void procinit0(void); void procflushseg(Segment*); void procpriority(Proc*, int, int); Proc* proctab(int); void procwired(Proc*, int); Pte* ptealloc(void); Pte* ptecpy(Pte*); int pullblock(Block**, int); Block* pullupblock(Block*, int); Block* pullupqueue(Queue*, int); void putmhead(Mhead*); void putmmu(ulong, ulong, Page*); void putpage(Page*); void putseg(Segment*); void putstr(char*); void putstrn(char*, int); void putswap(Page*); ulong pwait(Waitmsg*); Label* pwaserror(void); void qaddlist(Queue*, Block*); Block* qbread(Queue*, int); long qbwrite(Queue*, Block*); Queue* qbypass(void (*)(void*, Block*), void*); int qcanread(Queue*); void qclose(Queue*); int qconsume(Queue*, void*, int); Block* qcopy(Queue*, int, ulong); int qdiscard(Queue*, int); void qflush(Queue*); void qfree(Queue*); int qfull(Queue*); Block* qget(Queue*); void qhangup(Queue*, char*); int qisclosed(Queue*); void qinit(void); int qiwrite(Queue*, void*, int); int qlen(Queue*); void qlock(QLock*); Queue* qopen(int, int, void (*)(void*), void*); int qpass(Queue*, Block*); int qpassnolim(Queue*, Block*); int qproduce(Queue*, void*, int); void qputback(Queue*, Block*); long qread(Queue*, void*, int); Block* qremove(Queue*); void qreopen(Queue*); void qsetlimit(Queue*, int); void qunlock(QLock*); int qwindow(Queue*); int qwrite(Queue*, void*, int); void qnoblock(Queue*, int); int rand(void); void randominit(void); ulong randomread(void*, ulong); void rdb(void); int readnum(ulong, char*, ulong, ulong, int); int readstr(ulong, char*, ulong, char*); void ready(Proc*); void rebootcmd(int, char**); void reboot(void*, void*, ulong); void relocateseg(Segment*, ulong); void renameuser(char*, char*); void resched(char*); void resrcwait(char*); int return0(void*); void rlock(RWlock*); long rtctime(void); void runlock(RWlock*); Proc* runproc(void); void savefpregs(FPsave*); extern void (*saveintrts)(void); void sched(void); void scheddump(void); void schedinit(void); extern void (*screenputs)(char*, int); long seconds(void); ulong segattach(Proc*, ulong, char *, ulong, ulong); void segclock(ulong); void segpage(Segment*, Page*); void setkernur(Ureg*, Proc*); int setlabel(Label*); void setmalloctag(void*, uintptr); void setrealloctag(void*, ulong); void setregisters(Ureg*, char*, char*, int); void setswapchan(Chan*); long showfilewrite(char*, int); char* skipslash(char*); void sleep(Rendez*, int(*)(void*), void*); void* smalloc(ulong); int splhi(void); int spllo(void); void splx(int); void splxpc(int); char* srvname(Chan*); int swapcount(ulong); int swapfull(void); void swapinit(void); void timeradd(Timer*); void timerdel(Timer*); void timersinit(void); void timerintr(Ureg*, uvlong); void timerset(uvlong); ulong tk2ms(ulong); #define TK2MS(x) ((x)*(1000/HZ)) vlong todget(vlong*); void todfix(void); void todsetfreq(vlong); void todinit(void); void todset(vlong, vlong, int); Block* trimblock(Block*, int, int); void tsleep(Rendez*, int (*)(void*), void*, int); int uartctl(Uart*, char*); int uartgetc(void); void uartkick(void*); void uartmouse(Uart*, int (*)(Queue*, int), int); void uartputc(int); void uartputs(char*, int); void uartrecv(Uart*, char); Uart* uartsetup(Uart*); int uartstageoutput(Uart*); void unbreak(Proc*); void uncachepage(Page*); long unionread(Chan*, void*, long); void unlock(Lock*); Proc** uploc(void); void userinit(void); ulong userpc(void); long userwrite(char*, int); #define validaddr(a, b, c) void validname(char*, int); void validstat(uchar*, int); void vcacheinval(Page*, ulong); void* vmemchr(void*, int, int); Proc* wakeup(Rendez*); int walk(Chan**, char**, int, int, int*); #define waserror() (setjmp(pwaserror()->buf)) void wlock(RWlock*); void wunlock(RWlock*); void* xalloc(ulong); void* xallocz(ulong, int); void xfree(void*); void xhole(ulong, ulong); void xinit(void); int xmerge(void*, void*); void* xspanalloc(ulong, int, ulong); void xsummary(void); void yield(void); Segment* data2txt(Segment*); Segment* dupseg(Segment**, int, int); Segment* newseg(int, ulong, ulong); Segment* seg(Proc*, ulong, int); ulong ticks(void); void osproc(Proc*); void osnewproc(Proc*); void procsleep(void); void procwakeup(Proc*); void osinit(void); void screeninit(void); extern void terminit(void); drawterm-20170818/kern/netif.h000066400000000000000000000056061314554504700160470ustar00rootroot00000000000000typedef struct Etherpkt Etherpkt; typedef struct Netaddr Netaddr; typedef struct Netfile Netfile; typedef struct Netif Netif; enum { Nmaxaddr= 64, Nmhash= 31, Ncloneqid= 1, Naddrqid, N2ndqid, N3rdqid, Ndataqid, Nctlqid, Nstatqid, Ntypeqid, Nifstatqid, }; /* * Macros to manage Qid's used for multiplexed devices */ #define NETTYPE(x) (((ulong)x)&0x1f) #define NETID(x) ((((ulong)x))>>5) #define NETQID(i,t) ((((ulong)i)<<5)|(t)) /* * one per multiplexed connection */ struct Netfile { QLock lk; int inuse; ulong mode; char owner[KNAMELEN]; int type; /* multiplexor type */ int prom; /* promiscuous mode */ int scan; /* base station scanning interval */ int bridge; /* bridge mode */ int headersonly; /* headers only - no data */ uchar maddr[8]; /* bitmask of multicast addresses requested */ int nmaddr; /* number of multicast addresses */ Queue *in; /* input buffer */ }; /* * a network address */ struct Netaddr { Netaddr *next; /* allocation chain */ Netaddr *hnext; uchar addr[Nmaxaddr]; int ref; }; /* * a network interface */ struct Netif { QLock lk; /* multiplexing */ char name[KNAMELEN]; /* for top level directory */ int nfile; /* max number of Netfiles */ Netfile **f; /* about net */ int limit; /* flow control */ int alen; /* address length */ int mbps; /* megabits per sec */ uchar addr[Nmaxaddr]; uchar bcast[Nmaxaddr]; Netaddr *maddr; /* known multicast addresses */ int nmaddr; /* number of known multicast addresses */ Netaddr *mhash[Nmhash]; /* hash table of multicast addresses */ int prom; /* number of promiscuous opens */ int scan; /* number of base station scanners */ int all; /* number of -1 multiplexors */ /* statistics */ int misses; int inpackets; int outpackets; int crcs; /* input crc errors */ int oerrs; /* output errors */ int frames; /* framing errors */ int overflows; /* packet overflows */ int buffs; /* buffering errors */ int soverflows; /* software overflow */ /* routines for touching the hardware */ void *arg; void (*promiscuous)(void*, int); void (*multicast)(void*, uchar*, int); void (*scanbs)(void*, uint); /* scan for base stations */ }; void netifinit(Netif*, char*, int, ulong); Walkqid* netifwalk(Netif*, Chan*, Chan*, char **, int); Chan* netifopen(Netif*, Chan*, int); void netifclose(Netif*, Chan*); long netifread(Netif*, Chan*, void*, long, ulong); Block* netifbread(Netif*, Chan*, long, ulong); long netifwrite(Netif*, Chan*, void*, long); int netifwstat(Netif*, Chan*, uchar*, int); int netifstat(Netif*, Chan*, uchar*, int); int activemulti(Netif*, uchar*, int); /* * Ethernet specific */ enum { Eaddrlen= 6, ETHERMINTU = 60, /* minimum transmit size */ ETHERMAXTU = 1514, /* maximum transmit size */ ETHERHDRSIZE = 14, /* size of an ethernet header */ }; struct Etherpkt { uchar d[Eaddrlen]; uchar s[Eaddrlen]; uchar type[2]; uchar data[1500]; }; drawterm-20170818/kern/parse.c000066400000000000000000000037111314554504700160420ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" /* * Generous estimate of number of fields, including terminal nil pointer */ static int ncmdfield(char *p, int n) { int white, nwhite; char *ep; int nf; if(p == nil) return 1; nf = 0; ep = p+n; white = 1; /* first text will start field */ while(p < ep){ nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0); /* UTF is irrelevant */ if(white && !nwhite) /* beginning of field */ nf++; white = nwhite; } return nf+1; /* +1 for nil */ } /* * parse a command written to a device */ Cmdbuf* parsecmd(char *p, int n) { Cmdbuf *volatile cb; int nf; char *sp; nf = ncmdfield(p, n); /* allocate Cmdbuf plus string pointers plus copy of string including \0 */ sp = smalloc(sizeof(*cb) + nf * sizeof(char*) + n + 1); cb = (Cmdbuf*)sp; cb->f = (char**)(&cb[1]); cb->buf = (char*)(&cb->f[nf]); if(up!=nil && waserror()){ free(cb); nexterror(); } memmove(cb->buf, p, n); if(up != nil) poperror(); /* dump new line and null terminate */ if(n > 0 && cb->buf[n-1] == '\n') n--; cb->buf[n] = '\0'; cb->nf = tokenize(cb->buf, cb->f, nf-1); cb->f[cb->nf] = nil; return cb; } /* * Reconstruct original message, for error diagnostic */ void cmderror(Cmdbuf *cb, char *s) { int i; char *p, *e; p = up->genbuf; e = p+ERRMAX-10; p = seprint(p, e, "%s \"", s); for(i=0; inf; i++){ if(i > 0) p = seprint(p, e, " "); p = seprint(p, e, "%q", cb->f[i]); } strcpy(p, "\""); error(up->genbuf); } /* * Look up entry in table */ Cmdtab* lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab) { int i; Cmdtab *ct; if(cb->nf == 0) error("empty control message"); for(ct = ctab, i=0; icmd, "*") !=0) /* wildcard always matches */ if(strcmp(ct->cmd, cb->f[0]) != 0) continue; if(ct->narg != 0 && ct->narg != cb->nf) cmderror(cb, Ecmdargs); return ct; } cmderror(cb, "unknown control message"); return nil; } drawterm-20170818/kern/pgrp.c000066400000000000000000000076611314554504700157100ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" static Ref pgrpid; static Ref mountid; #ifdef NOTDEF void pgrpnote(ulong noteid, char *a, long n, int flag) { Proc *p, *ep; char buf[ERRMAX]; if(n >= ERRMAX-1) error(Etoobig); memmove(buf, a, n); buf[n] = 0; p = proctab(0); ep = p+conf.nproc; for(; p < ep; p++) { if(p->state == Dead) continue; if(up != p && p->noteid == noteid && p->kp == 0) { qlock(&p->debug); if(p->pid == 0 || p->noteid != noteid){ qunlock(&p->debug); continue; } if(!waserror()) { postnote(p, 0, buf, flag); poperror(); } qunlock(&p->debug); } } } #endif Pgrp* newpgrp(void) { Pgrp *p; p = smalloc(sizeof(Pgrp)); p->ref.ref = 1; p->pgrpid = incref(&pgrpid); return p; } Rgrp* newrgrp(void) { Rgrp *r; r = smalloc(sizeof(Rgrp)); r->ref.ref = 1; return r; } void closergrp(Rgrp *r) { if(decref(&r->ref) == 0) free(r); } void closepgrp(Pgrp *p) { Mhead **h, **e, *f, *next; if(decref(&p->ref) != 0) return; qlock(&p->debug); wlock(&p->ns); p->pgrpid = -1; e = &p->mnthash[MNTHASH]; for(h = p->mnthash; h < e; h++) { for(f = *h; f; f = next) { wlock(&f->lock); cclose(f->from); mountfree(f->mount); f->mount = nil; next = f->hash; wunlock(&f->lock); putmhead(f); } } wunlock(&p->ns); qunlock(&p->debug); free(p); } void pgrpinsert(Mount **order, Mount *m) { Mount *f; m->order = 0; if(*order == 0) { *order = m; return; } for(f = *order; f; f = f->order) { if(m->mountid < f->mountid) { m->order = f; *order = m; return; } order = &f->order; } *order = m; } /* * pgrpcpy MUST preserve the mountid allocation order of the parent group */ void pgrpcpy(Pgrp *to, Pgrp *from) { int i; Mount *n, *m, **link, *order; Mhead *f, **tom, **l, *mh; wlock(&from->ns); order = 0; tom = to->mnthash; for(i = 0; i < MNTHASH; i++) { l = tom++; for(f = from->mnthash[i]; f; f = f->hash) { rlock(&f->lock); mh = newmhead(f->from); *l = mh; l = &mh->hash; link = &mh->mount; for(m = f->mount; m; m = m->next) { n = newmount(mh, m->to, m->mflag, m->spec); m->copy = n; pgrpinsert(&order, m); *link = n; link = &n->next; } runlock(&f->lock); } } /* * Allocate mount ids in the same sequence as the parent group */ lock(&mountid.lk); for(m = order; m; m = m->order) m->copy->mountid = mountid.ref++; unlock(&mountid.lk); wunlock(&from->ns); } Fgrp* dupfgrp(Fgrp *f) { Fgrp *new; Chan *c; int i; new = smalloc(sizeof(Fgrp)); if(f == nil){ new->fd = smalloc(DELTAFD*sizeof(Chan*)); new->nfd = DELTAFD; new->ref.ref = 1; return new; } lock(&f->ref.lk); /* Make new fd list shorter if possible, preserving quantization */ new->nfd = f->maxfd+1; i = new->nfd%DELTAFD; if(i != 0) new->nfd += DELTAFD - i; new->fd = malloc(new->nfd*sizeof(Chan*)); if(new->fd == 0){ unlock(&f->ref.lk); error("no memory for fgrp"); } new->ref.ref = 1; new->maxfd = f->maxfd; for(i = 0; i <= f->maxfd; i++) { if((c = f->fd[i])){ incref(&c->ref); new->fd[i] = c; } } unlock(&f->ref.lk); return new; } void closefgrp(Fgrp *f) { int i; Chan *c; if(f == 0) return; if(decref(&f->ref) != 0) return; for(i = 0; i <= f->maxfd; i++) if((c = f->fd[i])) cclose(c); free(f->fd); free(f); } Mount* newmount(Mhead *mh, Chan *to, int flag, char *spec) { Mount *m; m = smalloc(sizeof(Mount)); m->to = to; m->head = mh; incref(&to->ref); m->mountid = incref(&mountid); m->mflag = flag; if(spec != 0) kstrdup(&m->spec, spec); return m; } void mountfree(Mount *m) { Mount *f; while(m) { f = m->next; cclose(m->to); m->mountid = 0; free(m->spec); free(m); m = f; } } #ifdef NOTDEF void resrcwait(char *reason) { char *p; if(up == 0) panic("resrcwait"); p = up->psstate; if(reason) { up->psstate = reason; print("%s\n", reason); } tsleep(&up->sleep, return0, 0, 300); up->psstate = p; } #endif drawterm-20170818/kern/posix.c000066400000000000000000000064021314554504700160720ustar00rootroot00000000000000/* * Posix generic OS implementation for drawterm. */ #include "u.h" #ifndef _XOPEN_SOURCE /* for Apple and OpenBSD; not sure if needed */ #define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include #include #include "lib.h" #include "dat.h" #include "fns.h" typedef struct Oproc Oproc; struct Oproc { int nsleep; int nwakeup; pthread_mutex_t mutex; pthread_cond_t cond; }; static pthread_key_t prdakey; Proc* _getproc(void) { void *v; if((v = pthread_getspecific(prdakey)) == nil) panic("cannot getspecific"); return v; } void _setproc(Proc *p) { if(pthread_setspecific(prdakey, p) != 0) panic("cannot setspecific"); } void osinit(void) { if(pthread_key_create(&prdakey, 0)) panic("cannot pthread_key_create"); } #undef pipe void osnewproc(Proc *p) { Oproc *op; pthread_mutexattr_t attr; op = (Oproc*)p->oproc; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); pthread_mutex_init(&op->mutex, &attr); pthread_mutexattr_destroy(&attr); pthread_cond_init(&op->cond, 0); } void osmsleep(int ms) { struct timeval tv; tv.tv_sec = ms / 1000; tv.tv_usec = (ms % 1000) * 1000; /* micro */ if(select(0, NULL, NULL, NULL, &tv) < 0) panic("select"); } void osyield(void) { sched_yield(); } void oserrstr(void) { char *p; if((p = strerror(errno)) != nil) strecpy(up->errstr, up->errstr+ERRMAX, p); else snprint(up->errstr, ERRMAX, "unix error %d", errno); } void oserror(void) { oserrstr(); nexterror(); } static void* tramp(void*); void osproc(Proc *p) { pthread_t pid; if(pthread_create(&pid, nil, tramp, p)){ oserrstr(); panic("osproc: %r"); } sched_yield(); } static void* tramp(void *vp) { Proc *p; p = vp; if(pthread_setspecific(prdakey, p)) panic("cannot setspecific"); (*p->fn)(p->arg); /* BUG: leaks Proc */ pthread_setspecific(prdakey, 0); pthread_exit(0); return 0; } void procsleep(void) { Proc *p; Oproc *op; p = up; op = (Oproc*)p->oproc; pthread_mutex_lock(&op->mutex); op->nsleep++; while(op->nsleep > op->nwakeup) pthread_cond_wait(&op->cond, &op->mutex); pthread_mutex_unlock(&op->mutex); } void procwakeup(Proc *p) { Oproc *op; op = (Oproc*)p->oproc; pthread_mutex_lock(&op->mutex); op->nwakeup++; if(op->nwakeup == op->nsleep) pthread_cond_signal(&op->cond); pthread_mutex_unlock(&op->mutex); } int randfd; #undef open void randominit(void) { #ifdef USE_RANDOM srandom(getpid()+fastticks(nil)+ticks()); #else if((randfd = open("/dev/urandom", OREAD)) < 0) if((randfd = open("/dev/random", OREAD)) < 0) panic("open /dev/random: %r"); #endif } #undef read ulong randomread(void *v, ulong n) { #ifdef USE_RANDOM int i; for(i=0; ifgrp = dupfgrp(nil); p->rgrp = newrgrp(); p->pgrp = newpgrp(); _setproc(p); up->slash = namec("#/", Atodir, 0, 0); cnameclose(up->slash->name); up->slash->name = newcname("/"); up->dot = cclone(up->slash); } Ref pidref; Proc* newproc(void) { Proc *p; p = mallocz(sizeof(Proc), 1); p->pid = incref(&pidref); strcpy(p->user, eve); p->syserrstr = p->errbuf0; p->errstr = p->errbuf1; strcpy(p->text, "drawterm"); osnewproc(p); return p; } int kproc(char *name, void (*fn)(void*), void *arg) { Proc *p; p = newproc(); p->fn = fn; p->arg = arg; p->slash = cclone(up->slash); p->dot = cclone(up->dot); p->rgrp = up->rgrp; if(p->rgrp) incref(&p->rgrp->ref); p->pgrp = up->pgrp; if(up->pgrp) incref(&up->pgrp->ref); p->fgrp = up->fgrp; if(p->fgrp) incref(&p->fgrp->ref); strecpy(p->text, p->text+sizeof p->text, name); osproc(p); return p->pid; } drawterm-20170818/kern/qio.c000066400000000000000000000557021314554504700155270ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" static ulong padblockcnt; static ulong concatblockcnt; static ulong pullupblockcnt; static ulong copyblockcnt; static ulong consumecnt; static ulong producecnt; static ulong qcopycnt; static int debugging; #define QDEBUG if(0) /* * IO queues */ struct Queue { Lock lk; Block* bfirst; /* buffer */ Block* blast; int len; /* bytes allocated to queue */ int dlen; /* data bytes in queue */ int limit; /* max bytes in queue */ int inilim; /* initial limit */ int state; int noblock; /* true if writes return immediately when q full */ int eof; /* number of eofs read by user */ void (*kick)(void*); /* restart output */ void (*bypass)(void*, Block*); /* bypass queue altogether */ void* arg; /* argument to kick */ QLock rlock; /* mutex for reading processes */ Rendez rr; /* process waiting to read */ QLock wlock; /* mutex for writing processes */ Rendez wr; /* process waiting to write */ char err[ERRMAX]; }; enum { Maxatomic = 64*1024, }; uint qiomaxatomic = Maxatomic; void ixsummary(void) { debugging ^= 1; iallocsummary(); print("pad %lud, concat %lud, pullup %lud, copy %lud\n", padblockcnt, concatblockcnt, pullupblockcnt, copyblockcnt); print("consume %lud, produce %lud, qcopy %lud\n", consumecnt, producecnt, qcopycnt); } /* * free a list of blocks */ void freeblist(Block *b) { Block *next; for(; b != 0; b = next){ next = b->next; b->next = 0; freeb(b); } } /* * pad a block to the front (or the back if size is negative) */ Block* padblock(Block *bp, int size) { int n; Block *nbp; QDEBUG checkb(bp, "padblock 1"); if(size >= 0){ if(bp->rp - bp->base >= size){ bp->rp -= size; return bp; } if(bp->next) panic("padblock 0x%p", getcallerpc(&bp)); n = BLEN(bp); padblockcnt++; nbp = allocb(size+n); nbp->rp += size; nbp->wp = nbp->rp; memmove(nbp->wp, bp->rp, n); nbp->wp += n; freeb(bp); nbp->rp -= size; } else { size = -size; if(bp->next) panic("padblock 0x%p", getcallerpc(&bp)); if(bp->lim - bp->wp >= size) return bp; n = BLEN(bp); padblockcnt++; nbp = allocb(size+n); memmove(nbp->wp, bp->rp, n); nbp->wp += n; freeb(bp); } QDEBUG checkb(nbp, "padblock 1"); return nbp; } /* * return count of bytes in a string of blocks */ int blocklen(Block *bp) { int len; len = 0; while(bp) { len += BLEN(bp); bp = bp->next; } return len; } /* * return count of space in blocks */ int blockalloclen(Block *bp) { int len; len = 0; while(bp) { len += BALLOC(bp); bp = bp->next; } return len; } /* * copy the string of blocks into * a single block and free the string */ Block* concatblock(Block *bp) { int len; Block *nb, *f; if(bp->next == 0) return bp; nb = allocb(blocklen(bp)); for(f = bp; f; f = f->next) { len = BLEN(f); memmove(nb->wp, f->rp, len); nb->wp += len; } concatblockcnt += BLEN(nb); freeblist(bp); QDEBUG checkb(nb, "concatblock 1"); return nb; } /* * make sure the first block has at least n bytes */ Block* pullupblock(Block *bp, int n) { int i; Block *nbp; /* * this should almost always be true, it's * just to avoid every caller checking. */ if(BLEN(bp) >= n) return bp; /* * if not enough room in the first block, * add another to the front of the list. */ if(bp->lim - bp->rp < n){ nbp = allocb(n); nbp->next = bp; bp = nbp; } /* * copy bytes from the trailing blocks into the first */ n -= BLEN(bp); while((nbp = bp->next)){ i = BLEN(nbp); if(i > n) { memmove(bp->wp, nbp->rp, n); pullupblockcnt++; bp->wp += n; nbp->rp += n; QDEBUG checkb(bp, "pullupblock 1"); return bp; } else { /* shouldn't happen but why crash if it does */ if(i < 0){ print("pullup negative length packet\n"); i = 0; } memmove(bp->wp, nbp->rp, i); pullupblockcnt++; bp->wp += i; bp->next = nbp->next; nbp->next = 0; freeb(nbp); n -= i; if(n == 0){ QDEBUG checkb(bp, "pullupblock 2"); return bp; } } } freeb(bp); return 0; } /* * make sure the first block has at least n bytes */ Block* pullupqueue(Queue *q, int n) { Block *b; if(BLEN(q->bfirst) >= n) return q->bfirst; q->bfirst = pullupblock(q->bfirst, n); for(b = q->bfirst; b != nil && b->next != nil; b = b->next) ; q->blast = b; return q->bfirst; } /* * trim to len bytes starting at offset */ Block * trimblock(Block *bp, int offset, int len) { ulong l; Block *nb, *startb; QDEBUG checkb(bp, "trimblock 1"); if(blocklen(bp) < offset+len) { freeblist(bp); return nil; } while((l = BLEN(bp)) < offset) { offset -= l; nb = bp->next; bp->next = nil; freeb(bp); bp = nb; } startb = bp; bp->rp += offset; while((l = BLEN(bp)) < len) { len -= l; bp = bp->next; } bp->wp -= (BLEN(bp) - len); if(bp->next) { freeblist(bp->next); bp->next = nil; } return startb; } /* * copy 'count' bytes into a new block */ Block* copyblock(Block *bp, int count) { int l; Block *nbp; QDEBUG checkb(bp, "copyblock 0"); nbp = allocb(count); for(; count > 0 && bp != 0; bp = bp->next){ l = BLEN(bp); if(l > count) l = count; memmove(nbp->wp, bp->rp, l); nbp->wp += l; count -= l; } if(count > 0){ memset(nbp->wp, 0, count); nbp->wp += count; } copyblockcnt++; QDEBUG checkb(nbp, "copyblock 1"); return nbp; } Block* adjustblock(Block* bp, int len) { int n; Block *nbp; if(len < 0){ freeb(bp); return nil; } if(bp->rp+len > bp->lim){ nbp = copyblock(bp, len); freeblist(bp); QDEBUG checkb(nbp, "adjustblock 1"); return nbp; } n = BLEN(bp); if(len > n) memset(bp->wp, 0, len-n); bp->wp = bp->rp+len; QDEBUG checkb(bp, "adjustblock 2"); return bp; } /* * throw away up to count bytes from a * list of blocks. Return count of bytes * thrown away. */ int pullblock(Block **bph, int count) { Block *bp; int n, bytes; bytes = 0; if(bph == nil) return 0; while(*bph != nil && count != 0) { bp = *bph; n = BLEN(bp); if(count < n) n = count; bytes += n; count -= n; bp->rp += n; QDEBUG checkb(bp, "pullblock "); if(BLEN(bp) == 0) { *bph = bp->next; bp->next = nil; freeb(bp); } } return bytes; } /* * get next block from a queue, return null if nothing there */ Block* qget(Queue *q) { int dowakeup; Block *b; /* sync with qwrite */ ilock(&q->lk); b = q->bfirst; if(b == nil){ q->state |= Qstarve; iunlock(&q->lk); return nil; } q->bfirst = b->next; b->next = 0; q->len -= BALLOC(b); q->dlen -= BLEN(b); QDEBUG checkb(b, "qget"); /* if writer flow controlled, restart */ if((q->state & Qflow) && q->len < q->limit/2){ q->state &= ~Qflow; dowakeup = 1; } else dowakeup = 0; iunlock(&q->lk); if(dowakeup) wakeup(&q->wr); return b; } /* * throw away the next 'len' bytes in the queue */ int qdiscard(Queue *q, int len) { Block *b; int dowakeup, n, sofar; ilock(&q->lk); for(sofar = 0; sofar < len; sofar += n){ b = q->bfirst; if(b == nil) break; QDEBUG checkb(b, "qdiscard"); n = BLEN(b); if(n <= len - sofar){ q->bfirst = b->next; b->next = 0; q->len -= BALLOC(b); q->dlen -= BLEN(b); freeb(b); } else { n = len - sofar; b->rp += n; q->dlen -= n; } } /* * if writer flow controlled, restart * * This used to be * q->len < q->limit/2 * but it slows down tcp too much for certain write sizes. * I really don't understand it completely. It may be * due to the queue draining so fast that the transmission * stalls waiting for the app to produce more data. - presotto */ if((q->state & Qflow) && q->len < q->limit){ q->state &= ~Qflow; dowakeup = 1; } else dowakeup = 0; iunlock(&q->lk); if(dowakeup) wakeup(&q->wr); return sofar; } /* * Interrupt level copy out of a queue, return # bytes copied. */ int qconsume(Queue *q, void *vp, int len) { Block *b; int n, dowakeup; uchar *p = vp; Block *tofree = nil; /* sync with qwrite */ ilock(&q->lk); for(;;) { b = q->bfirst; if(b == 0){ q->state |= Qstarve; iunlock(&q->lk); return -1; } QDEBUG checkb(b, "qconsume 1"); n = BLEN(b); if(n > 0) break; q->bfirst = b->next; q->len -= BALLOC(b); /* remember to free this */ b->next = tofree; tofree = b; }; if(n < len) len = n; memmove(p, b->rp, len); consumecnt += n; b->rp += len; q->dlen -= len; /* discard the block if we're done with it */ if((q->state & Qmsg) || len == n){ q->bfirst = b->next; b->next = 0; q->len -= BALLOC(b); q->dlen -= BLEN(b); /* remember to free this */ b->next = tofree; tofree = b; } /* if writer flow controlled, restart */ if((q->state & Qflow) && q->len < q->limit/2){ q->state &= ~Qflow; dowakeup = 1; } else dowakeup = 0; iunlock(&q->lk); if(dowakeup) wakeup(&q->wr); if(tofree != nil) freeblist(tofree); return len; } int qpass(Queue *q, Block *b) { int dlen, len, dowakeup; /* sync with qread */ dowakeup = 0; ilock(&q->lk); if(q->len >= q->limit){ freeblist(b); iunlock(&q->lk); return -1; } if(q->state & Qclosed){ freeblist(b); iunlock(&q->lk); return BALLOC(b); } /* add buffer to queue */ if(q->bfirst) q->blast->next = b; else q->bfirst = b; len = BALLOC(b); dlen = BLEN(b); QDEBUG checkb(b, "qpass"); while(b->next){ b = b->next; QDEBUG checkb(b, "qpass"); len += BALLOC(b); dlen += BLEN(b); } q->blast = b; q->len += len; q->dlen += dlen; if(q->len >= q->limit/2) q->state |= Qflow; if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } iunlock(&q->lk); if(dowakeup) wakeup(&q->rr); return len; } int qpassnolim(Queue *q, Block *b) { int dlen, len, dowakeup; /* sync with qread */ dowakeup = 0; ilock(&q->lk); if(q->state & Qclosed){ freeblist(b); iunlock(&q->lk); return BALLOC(b); } /* add buffer to queue */ if(q->bfirst) q->blast->next = b; else q->bfirst = b; len = BALLOC(b); dlen = BLEN(b); QDEBUG checkb(b, "qpass"); while(b->next){ b = b->next; QDEBUG checkb(b, "qpass"); len += BALLOC(b); dlen += BLEN(b); } q->blast = b; q->len += len; q->dlen += dlen; if(q->len >= q->limit/2) q->state |= Qflow; if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } iunlock(&q->lk); if(dowakeup) wakeup(&q->rr); return len; } /* * if the allocated space is way out of line with the used * space, reallocate to a smaller block */ Block* packblock(Block *bp) { Block **l, *nbp; int n; for(l = &bp; *l; l = &(*l)->next){ nbp = *l; n = BLEN(nbp); if((n<<2) < BALLOC(nbp)){ *l = allocb(n); memmove((*l)->wp, nbp->rp, n); (*l)->wp += n; (*l)->next = nbp->next; freeb(nbp); } } return bp; } int qproduce(Queue *q, void *vp, int len) { Block *b; int dowakeup; uchar *p = vp; /* sync with qread */ dowakeup = 0; ilock(&q->lk); /* no waiting receivers, room in buffer? */ if(q->len >= q->limit){ q->state |= Qflow; iunlock(&q->lk); return -1; } /* save in buffer */ b = iallocb(len); if(b == 0){ iunlock(&q->lk); return 0; } memmove(b->wp, p, len); producecnt += len; b->wp += len; if(q->bfirst) q->blast->next = b; else q->bfirst = b; q->blast = b; /* b->next = 0; done by iallocb() */ q->len += BALLOC(b); q->dlen += BLEN(b); QDEBUG checkb(b, "qproduce"); if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } if(q->len >= q->limit) q->state |= Qflow; iunlock(&q->lk); if(dowakeup) wakeup(&q->rr); return len; } /* * copy from offset in the queue */ Block* qcopy(Queue *q, int len, ulong offset) { int sofar; int n; Block *b, *nb; uchar *p; nb = allocb(len); ilock(&q->lk); /* go to offset */ b = q->bfirst; for(sofar = 0; ; sofar += n){ if(b == nil){ iunlock(&q->lk); return nb; } n = BLEN(b); if(sofar + n > offset){ p = b->rp + offset - sofar; n -= offset - sofar; break; } QDEBUG checkb(b, "qcopy"); b = b->next; } /* copy bytes from there */ for(sofar = 0; sofar < len;){ if(n > len - sofar) n = len - sofar; memmove(nb->wp, p, n); qcopycnt += n; sofar += n; nb->wp += n; b = b->next; if(b == nil) break; n = BLEN(b); p = b->rp; } iunlock(&q->lk); return nb; } /* * called by non-interrupt code */ Queue* qopen(int limit, int msg, void (*kick)(void*), void *arg) { Queue *q; q = malloc(sizeof(Queue)); if(q == 0) return 0; q->limit = q->inilim = limit; q->kick = kick; q->arg = arg; q->state = msg; q->state |= Qstarve; q->eof = 0; q->noblock = 0; return q; } /* open a queue to be bypassed */ Queue* qbypass(void (*bypass)(void*, Block*), void *arg) { Queue *q; q = malloc(sizeof(Queue)); if(q == 0) return 0; q->limit = 0; q->arg = arg; q->bypass = bypass; q->state = 0; return q; } static int notempty(void *a) { Queue *q = a; return (q->state & Qclosed) || q->bfirst != 0; } /* * wait for the queue to be non-empty or closed. * called with q ilocked. */ static int qwait(Queue *q) { /* wait for data */ for(;;){ if(q->bfirst != nil) break; if(q->state & Qclosed){ if(++q->eof > 3) return -1; if(*q->err && strcmp(q->err, Ehungup) != 0) return -1; return 0; } q->state |= Qstarve; /* flag requesting producer to wake me */ iunlock(&q->lk); sleep(&q->rr, notempty, q); ilock(&q->lk); } return 1; } /* * add a block list to a queue */ void qaddlist(Queue *q, Block *b) { /* queue the block */ if(q->bfirst) q->blast->next = b; else q->bfirst = b; q->len += blockalloclen(b); q->dlen += blocklen(b); while(b->next) b = b->next; q->blast = b; } /* * called with q ilocked */ Block* qremove(Queue *q) { Block *b; b = q->bfirst; if(b == nil) return nil; q->bfirst = b->next; b->next = nil; q->dlen -= BLEN(b); q->len -= BALLOC(b); QDEBUG checkb(b, "qremove"); return b; } /* * copy the contents of a string of blocks into * memory. emptied blocks are freed. return * pointer to first unconsumed block. */ Block* bl2mem(uchar *p, Block *b, int n) { int i; Block *next; for(; b != nil; b = next){ i = BLEN(b); if(i > n){ memmove(p, b->rp, n); b->rp += n; return b; } memmove(p, b->rp, i); n -= i; p += i; b->rp += i; next = b->next; freeb(b); } return nil; } /* * copy the contents of memory into a string of blocks. * return nil on error. */ Block* mem2bl(uchar *p, int len) { int n; Block *b, *first, **l; first = nil; l = &first; if(waserror()){ freeblist(first); nexterror(); } do { n = len; if(n > Maxatomic) n = Maxatomic; *l = b = allocb(n); /* setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]); */ memmove(b->wp, p, n); b->wp += n; p += n; len -= n; l = &b->next; } while(len > 0); poperror(); return first; } /* * put a block back to the front of the queue * called with q ilocked */ void qputback(Queue *q, Block *b) { b->next = q->bfirst; if(q->bfirst == nil) q->blast = b; q->bfirst = b; q->len += BALLOC(b); q->dlen += BLEN(b); } /* * flow control, get producer going again * called with q ilocked */ static void qwakeup_iunlock(Queue *q) { int dowakeup = 0; /* if writer flow controlled, restart */ if((q->state & Qflow) && q->len < q->limit/2){ q->state &= ~Qflow; dowakeup = 1; } iunlock(&q->lk); /* wakeup flow controlled writers */ if(dowakeup){ if(q->kick) q->kick(q->arg); wakeup(&q->wr); } } /* * get next block from a queue (up to a limit) */ Block* qbread(Queue *q, int len) { Block *b, *nb; int n; qlock(&q->rlock); if(waserror()){ qunlock(&q->rlock); nexterror(); } ilock(&q->lk); switch(qwait(q)){ case 0: /* queue closed */ iunlock(&q->lk); qunlock(&q->rlock); poperror(); return nil; case -1: /* multiple reads on a closed queue */ iunlock(&q->lk); error(q->err); } /* if we get here, there's at least one block in the queue */ b = qremove(q); n = BLEN(b); /* split block if it's too big and this is not a message queue */ nb = b; if(n > len){ if((q->state&Qmsg) == 0){ n -= len; b = allocb(n); memmove(b->wp, nb->rp+len, n); b->wp += n; qputback(q, b); } nb->wp = nb->rp + len; } /* restart producer */ qwakeup_iunlock(q); poperror(); qunlock(&q->rlock); return nb; } /* * read a queue. if no data is queued, post a Block * and wait on its Rendez. */ long qread(Queue *q, void *vp, int len) { Block *b, *first, **l; int m, n; qlock(&q->rlock); if(waserror()){ qunlock(&q->rlock); nexterror(); } ilock(&q->lk); again: switch(qwait(q)){ case 0: /* queue closed */ iunlock(&q->lk); qunlock(&q->rlock); poperror(); return 0; case -1: /* multiple reads on a closed queue */ iunlock(&q->lk); error(q->err); } /* if we get here, there's at least one block in the queue */ if(q->state & Qcoalesce){ /* when coalescing, 0 length blocks just go away */ b = q->bfirst; if(BLEN(b) <= 0){ freeb(qremove(q)); goto again; } /* grab the first block plus as many * following blocks as will completely * fit in the read. */ n = 0; l = &first; m = BLEN(b); for(;;) { *l = qremove(q); l = &b->next; n += m; b = q->bfirst; if(b == nil) break; m = BLEN(b); if(n+m > len) break; } } else { first = qremove(q); n = BLEN(first); } /* copy to user space outside of the ilock */ iunlock(&q->lk); b = bl2mem(vp, first, len); ilock(&q->lk); /* take care of any left over partial block */ if(b != nil){ n -= BLEN(b); if(q->state & Qmsg) freeb(b); else qputback(q, b); } /* restart producer */ qwakeup_iunlock(q); poperror(); qunlock(&q->rlock); return n; } static int qnotfull(void *a) { Queue *q = a; return q->len < q->limit || (q->state & Qclosed); } ulong noblockcnt; /* * add a block to a queue obeying flow control */ long qbwrite(Queue *q, Block *b) { int n, dowakeup; n = BLEN(b); if(q->bypass){ (*q->bypass)(q->arg, b); return n; } dowakeup = 0; qlock(&q->wlock); if(waserror()){ if(b != nil) freeb(b); qunlock(&q->wlock); nexterror(); } ilock(&q->lk); /* give up if the queue is closed */ if(q->state & Qclosed){ iunlock(&q->lk); error(q->err); } /* if nonblocking, don't queue over the limit */ if(q->len >= q->limit){ if(q->noblock){ iunlock(&q->lk); freeb(b); noblockcnt += n; qunlock(&q->wlock); poperror(); return n; } } /* queue the block */ if(q->bfirst) q->blast->next = b; else q->bfirst = b; q->blast = b; b->next = 0; q->len += BALLOC(b); q->dlen += n; QDEBUG checkb(b, "qbwrite"); b = nil; /* make sure other end gets awakened */ if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } iunlock(&q->lk); /* get output going again */ if(q->kick && (dowakeup || (q->state&Qkick))) q->kick(q->arg); /* wakeup anyone consuming at the other end */ if(dowakeup){ wakeup(&q->rr); /* if we just wokeup a higher priority process, let it run */ /* p = wakeup(&q->rr); if(p != nil && p->priority > up->priority) sched(); */ } /* * flow control, wait for queue to get below the limit * before allowing the process to continue and queue * more. We do this here so that postnote can only * interrupt us after the data has been queued. This * means that things like 9p flushes and ssl messages * will not be disrupted by software interrupts. * * Note - this is moderately dangerous since a process * that keeps getting interrupted and rewriting will * queue infinite crud. */ for(;;){ if(q->noblock || qnotfull(q)) break; ilock(&q->lk); q->state |= Qflow; iunlock(&q->lk); sleep(&q->wr, qnotfull, q); } USED(b); qunlock(&q->wlock); poperror(); return n; } /* * write to a queue. only Maxatomic bytes at a time is atomic. */ int qwrite(Queue *q, void *vp, int len) { int n, sofar; Block *b; uchar *p = vp; QDEBUG if(!islo()) print("qwrite hi %p\n", getcallerpc(&q)); sofar = 0; do { n = len-sofar; if(n > Maxatomic) n = Maxatomic; b = allocb(n); /* setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]); */ if(waserror()){ freeb(b); nexterror(); } memmove(b->wp, p+sofar, n); poperror(); b->wp += n; qbwrite(q, b); sofar += n; } while(sofar < len && (q->state & Qmsg) == 0); return len; } /* * used by print() to write to a queue. Since we may be splhi or not in * a process, don't qlock. */ int qiwrite(Queue *q, void *vp, int len) { int n, sofar, dowakeup; Block *b; uchar *p = vp; dowakeup = 0; sofar = 0; do { n = len-sofar; if(n > Maxatomic) n = Maxatomic; b = iallocb(n); if(b == nil) break; memmove(b->wp, p+sofar, n); b->wp += n; ilock(&q->lk); QDEBUG checkb(b, "qiwrite"); if(q->bfirst) q->blast->next = b; else q->bfirst = b; q->blast = b; q->len += BALLOC(b); q->dlen += n; if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } iunlock(&q->lk); if(dowakeup){ if(q->kick) q->kick(q->arg); wakeup(&q->rr); } sofar += n; } while(sofar < len && (q->state & Qmsg) == 0); return sofar; } /* * be extremely careful when calling this, * as there is no reference accounting */ void qfree(Queue *q) { qclose(q); free(q); } /* * Mark a queue as closed. No further IO is permitted. * All blocks are released. */ void qclose(Queue *q) { Block *bfirst; if(q == nil) return; /* mark it */ ilock(&q->lk); q->state |= Qclosed; q->state &= ~(Qflow|Qstarve); strcpy(q->err, Ehungup); bfirst = q->bfirst; q->bfirst = 0; q->len = 0; q->dlen = 0; q->noblock = 0; iunlock(&q->lk); /* free queued blocks */ freeblist(bfirst); /* wake up readers/writers */ wakeup(&q->rr); wakeup(&q->wr); } /* * Mark a queue as closed. Wakeup any readers. Don't remove queued * blocks. */ void qhangup(Queue *q, char *msg) { /* mark it */ ilock(&q->lk); q->state |= Qclosed; if(msg == 0 || *msg == 0) strcpy(q->err, Ehungup); else strncpy(q->err, msg, ERRMAX-1); iunlock(&q->lk); /* wake up readers/writers */ wakeup(&q->rr); wakeup(&q->wr); } /* * return non-zero if the q is hungup */ int qisclosed(Queue *q) { return q->state & Qclosed; } /* * mark a queue as no longer hung up */ void qreopen(Queue *q) { ilock(&q->lk); q->state &= ~Qclosed; q->state |= Qstarve; q->eof = 0; q->limit = q->inilim; iunlock(&q->lk); } /* * return bytes queued */ int qlen(Queue *q) { return q->dlen; } /* * return space remaining before flow control */ int qwindow(Queue *q) { int l; l = q->limit - q->len; if(l < 0) l = 0; return l; } /* * return true if we can read without blocking */ int qcanread(Queue *q) { return q->bfirst!=0; } /* * change queue limit */ void qsetlimit(Queue *q, int limit) { q->limit = limit; } /* * set blocking/nonblocking */ void qnoblock(Queue *q, int onoff) { q->noblock = onoff; } /* * flush the output queue */ void qflush(Queue *q) { Block *bfirst; /* mark it */ ilock(&q->lk); bfirst = q->bfirst; q->bfirst = 0; q->len = 0; q->dlen = 0; iunlock(&q->lk); /* free queued blocks */ freeblist(bfirst); /* wake up readers/writers */ wakeup(&q->wr); } int qfull(Queue *q) { return q->state & Qflow; } int qstate(Queue *q) { return q->state; } drawterm-20170818/kern/qlock.c000066400000000000000000000021371314554504700160420ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" static void queue(Proc **first, Proc **last) { Proc *t; t = *last; if(t == 0) *first = up; else t->qnext = up; *last = up; up->qnext = 0; } static Proc* dequeue(Proc **first, Proc **last) { Proc *t; t = *first; if(t == 0) return 0; *first = t->qnext; if(*first == 0) *last = 0; return t; } void qlock(QLock *q) { lock(&q->lk); if(q->hold == 0) { q->hold = up; unlock(&q->lk); return; } /* * Can't assert this because of RWLock assert(q->hold != up); */ queue((Proc**)&q->first, (Proc**)&q->last); unlock(&q->lk); procsleep(); } int canqlock(QLock *q) { lock(&q->lk); if(q->hold == 0) { q->hold = up; unlock(&q->lk); return 1; } unlock(&q->lk); return 0; } void qunlock(QLock *q) { Proc *p; lock(&q->lk); /* * Can't assert this because of RWlock assert(q->hold == CT); */ p = dequeue((Proc**)&q->first, (Proc**)&q->last); if(p) { q->hold = p; unlock(&q->lk); procwakeup(p); } else { q->hold = 0; unlock(&q->lk); } } int holdqlock(QLock *q) { return q->hold == up; } drawterm-20170818/kern/rendez.c000066400000000000000000000024151314554504700162170ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" void sleep(Rendez *r, int (*f)(void*), void *arg) { int s; s = splhi(); lock(&r->lk); lock(&up->rlock); if(r->p){ print("double sleep %lud %lud\n", r->p->pid, up->pid); dumpstack(); } /* * Wakeup only knows there may be something to do by testing * r->p in order to get something to lock on. * Flush that information out to memory in case the sleep is * committed. */ r->p = up; if((*f)(arg) || up->notepending){ /* * if condition happened or a note is pending * never mind */ r->p = nil; unlock(&up->rlock); unlock(&r->lk); } else { /* * now we are committed to * change state and call scheduler */ up->state = Wakeme; up->r = r; /* statistics */ /* m->cs++; */ unlock(&up->rlock); unlock(&r->lk); procsleep(); } if(up->notepending) { up->notepending = 0; splx(s); error(Eintr); } splx(s); } Proc* wakeup(Rendez *r) { Proc *p; int s; s = splhi(); lock(&r->lk); p = r->p; if(p != nil){ lock(&p->rlock); if(p->state != Wakeme || p->r != r) panic("wakeup: state"); r->p = nil; p->r = nil; p->state = Running; procwakeup(p); unlock(&p->rlock); } unlock(&r->lk); splx(s); return p; } drawterm-20170818/kern/rwlock.c000066400000000000000000000011721314554504700162300ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" void rlock(RWlock *l) { qlock(&l->x); /* wait here for writers and exclusion */ lock(&l->lk); l->readers++; canqlock(&l->k); /* block writers if we are the first reader */ unlock(&l->lk); qunlock(&l->x); } void runlock(RWlock *l) { lock(&l->lk); if(--l->readers == 0) /* last reader out allows writers */ qunlock(&l->k); unlock(&l->lk); } void wlock(RWlock *l) { qlock(&l->x); /* wait here for writers and exclusion */ qlock(&l->k); /* wait here for last reader */ } void wunlock(RWlock *l) { qunlock(&l->k); qunlock(&l->x); } drawterm-20170818/kern/screen.h000066400000000000000000000023321314554504700162120ustar00rootroot00000000000000typedef struct Mouseinfo Mouseinfo; typedef struct Mousestate Mousestate; typedef struct Cursorinfo Cursorinfo; typedef struct Screeninfo Screeninfo; #define Mousequeue 16 /* queue can only have Mousequeue-1 elements */ #define Mousewindow 500 /* mouse event window in millisec */ struct Mousestate { int buttons; Point xy; ulong msec; }; struct Mouseinfo { Lock lk; Mousestate queue[Mousequeue]; int ri, wi; int lastb; int trans; int open; Rendez r; }; struct Cursorinfo { Lock lk; Point offset; uchar clr[2*16]; uchar set[2*16]; }; struct Screeninfo { Lock lk; Memimage *newsoft; int reshaped; int depth; int dibtype; }; extern Memimage *gscreen; extern Mouseinfo mouse; extern Cursorinfo cursor; extern Screeninfo screen; void screeninit(void); void screenload(Rectangle, int, uchar *, Point, int); void getcolor(ulong, ulong*, ulong*, ulong*); void setcolor(ulong, ulong, ulong, ulong); void refreshrect(Rectangle); void cursorarrow(void); void setcursor(void); void mouseset(Point); void drawflushr(Rectangle); void flushmemscreen(Rectangle); uchar *attachscreen(Rectangle*, ulong*, int*, int*, int*, void**); void drawqlock(void); void drawqunlock(void); int drawcanqlock(void); void terminit(void); drawterm-20170818/kern/sleep.c000066400000000000000000000024151314554504700160400ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" void sleep(Rendez *r, int (*f)(void*), void *arg) { int s; s = splhi(); lock(&r->lk); lock(&up->rlock); if(r->p){ print("double sleep %lud %lud\n", r->p->pid, up->pid); dumpstack(); } /* * Wakeup only knows there may be something to do by testing * r->p in order to get something to lock on. * Flush that information out to memory in case the sleep is * committed. */ r->p = up; if((*f)(arg) || up->notepending){ /* * if condition happened or a note is pending * never mind */ r->p = nil; unlock(&up->rlock); unlock(&r->lk); } else { /* * now we are committed to * change state and call scheduler */ up->state = Wakeme; up->r = r; /* statistics */ /* m->cs++; */ unlock(&up->rlock); unlock(&r->lk); procsleep(); } if(up->notepending) { up->notepending = 0; splx(s); error(Eintr); } splx(s); } Proc* wakeup(Rendez *r) { Proc *p; int s; s = splhi(); lock(&r->lk); p = r->p; if(p != nil){ lock(&p->rlock); if(p->state != Wakeme || p->r != r) panic("wakeup: state"); r->p = nil; p->r = nil; p->state = Running; procwakeup(p); unlock(&p->rlock); } unlock(&r->lk); splx(s); return p; } drawterm-20170818/kern/smalloc.c000066400000000000000000000002731314554504700163620ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" void* smalloc(ulong n) { return mallocz(n, 1); } void* malloc(ulong n) { return mallocz(n, 1); } drawterm-20170818/kern/stub.c000066400000000000000000000023731314554504700157100ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" void mallocsummary(void) { } void pagersummary(void) { } int iseve(void) { return 1; } void setswapchan(Chan *c) { USED(c); } void splx(int x) { USED(x); } int splhi(void) { return 0; } int spllo(void) { return 0; } void procdump(void) { } void scheddump(void) { } void killbig(void) { } void dumpstack(void) { } void xsummary(void) { } void rebootcmd(int argc, char **argv) { USED(argc); USED(argv); } void kickpager(void) { } int userwrite(char *a, int n) { error(Eperm); return 0; } vlong todget(vlong *p) { if(p) *p = 0; return 0; } void todset(vlong a, vlong b, int c) { USED(a); USED(b); USED(c); } void todsetfreq(vlong a) { USED(a); } long hostdomainwrite(char *a, int n) { USED(a); USED(n); error(Eperm); return 0; } long hostownerwrite(char *a, int n) { USED(a); USED(n); error(Eperm); return 0; } void todinit(void) { } void rdb(void) { } void setmalloctag(void *v, uintptr tag) { USED(v); USED(tag); } int postnote(Proc *p, int x, char *msg, int flag) { USED(p); USED(x); USED(msg); USED(flag); return 0; } void exhausted(char *s) { panic("out of %s", s); } uvlong fastticks(uvlong *v) { if(v) *v = 1; return 0; } drawterm-20170818/kern/syscall.c000066400000000000000000000311141314554504700164000ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" Chan* fdtochan(int fd, int mode, int chkmnt, int iref) { Fgrp *f; Chan *c; c = 0; f = up->fgrp; lock(&f->ref.lk); if(fd<0 || NFD<=fd || (c = f->fd[fd])==0) { unlock(&f->ref.lk); error(Ebadfd); } if(iref) refinc(&c->ref); unlock(&f->ref.lk); if(chkmnt && (c->flag&CMSG)) goto bad; if(mode<0 || c->mode==ORDWR) return c; if((mode&OTRUNC) && c->mode==OREAD) goto bad; if((mode&~OTRUNC) != c->mode) goto bad; return c; bad: if(iref) cclose(c); error(Ebadusefd); return nil; /* shut up compiler */ } static void fdclose(int fd, int flag) { int i; Chan *c; Fgrp *f; f = up->fgrp; lock(&f->ref.lk); c = f->fd[fd]; if(c == 0) { unlock(&f->ref.lk); return; } if(flag) { if(c==0 || !(c->flag&flag)) { unlock(&f->ref.lk); return; } } f->fd[fd] = 0; if(fd == f->maxfd) for(i=fd; --i>=0 && f->fd[i]==0; ) f->maxfd = i; unlock(&f->ref.lk); cclose(c); } static int newfd(Chan *c) { int i; Fgrp *f; f = up->fgrp; lock(&f->ref.lk); for(i=0; ifd[i] == 0){ if(i > f->maxfd) f->maxfd = i; f->fd[i] = c; unlock(&f->ref.lk); return i; } unlock(&f->ref.lk); error("no file descriptors"); return 0; } int sysclose(int fd) { if(waserror()) return -1; fdtochan(fd, -1, 0, 0); fdclose(fd, 0); poperror(); return 0; } int syscreate(char *path, int mode, ulong perm) { int fd; Chan *c = 0; if(waserror()) { cclose(c); return -1; } openmode(mode); /* error check only */ c = namec(path, Acreate, mode, perm); fd = newfd((Chan*)c); poperror(); return fd; } int sysdup(int old, int new) { Chan *oc; Fgrp *f = up->fgrp; Chan *c = 0; if(waserror()) return -1; c = fdtochan(old, -1, 0, 1); if(new != -1) { if(new < 0 || NFD <= new) { cclose(c); error(Ebadfd); } lock(&f->ref.lk); if(new > f->maxfd) f->maxfd = new; oc = f->fd[new]; f->fd[new] = (Chan*)c; unlock(&f->ref.lk); if(oc != 0) cclose(oc); } else { if(waserror()) { cclose(c); nexterror(); } new = newfd((Chan*)c); poperror(); } poperror(); return new; } int sysfstat(int fd, char *buf) { Chan *c = 0; if(waserror()) { cclose(c); return -1; } c = fdtochan(fd, -1, 0, 1); devtab[c->type]->stat((Chan*)c, buf); poperror(); cclose(c); return 0; } int sysfwstat(int fd, char *buf) { Chan *c = 0; if(waserror()) { cclose(c); return -1; } nameok(buf); c = fdtochan(fd, -1, 1, 1); devtab[c->type]->wstat((Chan*)c, buf); poperror(); cclose(c); return 0; } int syschdir(char *dir) { return 0; } long bindmount(Chan *c0, char *old, int flag, char *spec) { int ret; Chan *c1 = 0; if(flag>MMASK || (flag&MORDER) == (MBEFORE|MAFTER)) error(Ebadarg); c1 = namec(old, Amount, 0, 0); if(waserror()){ cclose(c1); nexterror(); } ret = cmount(c0, c1, flag, spec); poperror(); cclose(c1); return ret; } int sysbind(char *new, char *old, int flags) { long r; Chan *c0 = 0; if(waserror()) { cclose(c0); return -1; } c0 = namec(new, Aaccess, 0, 0); r = bindmount(c0, old, flags, ""); poperror(); cclose(c0); return 0; } int sysmount(int fd, char *old, int flags, char *spec) { long r; Chan *c0 = 0, *bc = 0; struct { Chan* chan; char* spec; int flags; } mntparam; if(waserror()) { cclose(bc); cclose(c0); return -1; } bc = fdtochan(fd, ORDWR, 0, 1); mntparam.chan = (Chan*)bc; mntparam.spec = spec; mntparam.flags = flags; c0 = (*devtab[devno('M', 0)].attach)(&mntparam); cclose(bc); r = bindmount(c0, old, flags, spec); poperror(); cclose(c0); return r; } int sysunmount(char *old, char *new) { Chan *cmount = 0, *cmounted = 0; if(waserror()) { cclose(cmount); cclose(cmounted); return -1; } cmount = namec(new, Amount, OREAD, 0); if(old != 0) cmounted = namec(old, Aopen, OREAD, 0); cunmount(cmount, cmounted); poperror(); cclose(cmount); cclose(cmounted); return 0; } int sysopen(char *path, int mode) { int fd; Chan *c = 0; if(waserror()){ cclose(c); return -1; } openmode(mode); /* error check only */ c = namec(path, Aopen, mode, 0); fd = newfd((Chan*)c); poperror(); return fd; } long unionread(Chan *c, void *va, long n) { long nr; Chan *nc = 0; Pgrp *pg = 0; pg = up->pgrp; rlock(&pg->ns); for(;;) { if(waserror()) { runlock(&pg->ns); nexterror(); } nc = clone(c->mnt->to, 0); poperror(); if(c->mountid != c->mnt->mountid) { runlock(&pg->ns); cclose(nc); return 0; } /* Error causes component of union to be skipped */ if(waserror()) { cclose(nc); goto next; } nc = (*devtab[nc->type].open)((Chan*)nc, OREAD); nc->offset = c->offset; nr = (*devtab[nc->type].read)((Chan*)nc, va, n, nc->offset); /* devdirread e.g. changes it */ c->offset = nc->offset; poperror(); cclose(nc); if(nr > 0) { runlock(&pg->ns); return nr; } /* Advance to next element */ next: c->mnt = c->mnt->next; if(c->mnt == 0) break; c->mountid = c->mnt->mountid; c->offset = 0; } runlock(&pg->ns); return 0; } long sysread(int fd, void *va, long n) { int dir; Lock *cl; Chan *c = 0; if(waserror()) { cclose(c); return -1; } c = fdtochan(fd, OREAD, 1, 1); dir = c->qid.path&CHDIR; if(dir) { n -= n%DIRLEN; if(c->offset%DIRLEN || n==0) error(Etoosmall); } if(dir && c->mnt) n = unionread((Chan*)c, va, n); else n = (*devtab[c->type].read)((Chan*)c, va, n, c->offset); cl = (Lock*)&c->r.l; lock(cl); c->offset += n; unlock(cl); poperror(); cclose(c); return n; } int sysremove(char *path) { Chan *c = 0; if(waserror()) { if(c != 0) c->type = 0; /* see below */ cclose(c); return -1; } c = namec(path, Aaccess, 0, 0); (*devtab[c->type].remove)((Chan*)c); /* * Remove clunks the fid, but we need to recover the Chan * so fake it up. rootclose() is known to be a nop. */ c->type = 0; poperror(); cclose(c); return 0; } long sysseek(int fd, long off, int whence) { Dir dir; Chan *c; char buf[DIRLEN]; if(waserror()) return -1; c = fdtochan(fd, -1, 1, 0); if(c->qid.path & CHDIR) error(Eisdir); switch(whence) { case 0: c->offset = off; break; case 1: lock(&c->r.l); /* lock for read/write update */ c->offset += off; off = c->offset; unlock(&c->r.l); break; case 2: (*devtab[c->type].stat)(c, buf); convM2D(buf, &dir); c->offset = dir.length + off; off = c->offset; break; } poperror(); return off; } int sysstat(char *path, char *buf) { Chan *c = 0; if(waserror()){ cclose(c); return -1; } c = namec(path, Aaccess, 0, 0); (*devtab[c->type].stat)((Chan*)c, buf); poperror(); cclose(c); return 0; } long syswrite(int fd, void *va, long n) { Lock *cl; Chan *c = 0; if(waserror()) { cclose(c); return -1; } c = fdtochan(fd, OWRITE, 1, 1); if(c->qid.path & CHDIR) error(Eisdir); n = (*devtab[c->type].write)((Chan*)c, va, n, c->offset); cl = (Lock*)&c->r.l; lock(cl); c->offset += n; unlock(cl); poperror(); cclose(c); return n; } int syswstat(char *path, char *buf) { Chan *c = 0; if(waserror()) { cclose(c); return -1; } nameok(buf); c = namec(path, Aaccess, 0, 0); (*devtab[c->type].wstat)((Chan*)c, buf); poperror(); cclose(c); return 0; } int sysdirstat(char *name, Dir *dir) { char buf[DIRLEN]; if(sysstat(name, buf) == -1) return -1; convM2D(buf, dir); return 0; } int sysdirfstat(int fd, Dir *dir) { char buf[DIRLEN]; if(sysfstat(fd, buf) == -1) return -1; convM2D(buf, dir); return 0; } int sysdirwstat(char *name, Dir *dir) { char buf[DIRLEN]; convD2M(dir, buf); return syswstat(name, buf); } int sysdirfwstat(int fd, Dir *dir) { char buf[DIRLEN]; convD2M(dir, buf); return sysfwstat(fd, buf); } long sysdirread(int fd, Dir *dbuf, long count) { int c, n, i, r; char buf[DIRLEN*50]; n = 0; count = (count/sizeof(Dir)) * DIRLEN; while(n < count) { c = count - n; if(c > sizeof(buf)) c = sizeof(buf); r = sysread(fd, buf, c); if(r == 0) break; if(r < 0 || r % DIRLEN) return -1; for(i=0; i 0){ net[n] = 0; p = strchr(net, ' '); if(p == 0) continue; *p++ = 0; rv = call(net, p, cfdp, dir, local); if(rv >= 0) break; } sysclose(fd); return rv; } static int identtrans(char *addr, char *naddr, int na, char *file, int nf) { char *p; char reply[4*NAMELEN]; /* parse the network */ strncpy(reply, addr, sizeof(reply)); reply[sizeof(reply)-1] = 0; p = strchr(reply, '!'); if(p) *p++ = 0; sprint(file, "/net/%.*s/clone", na - sizeof("/net//clone"), reply); strncpy(naddr, p, na); naddr[na-1] = 0; return 1; } static int nettrans(char *addr, char *naddr, int na, char *file, int nf) { long n; int fd; char *cp; char reply[4*NAMELEN]; /* * ask the connection server */ fd = sysopen("/net/cs", ORDWR); if(fd < 0) return identtrans(addr, naddr, na, file, nf); if(syswrite(fd, addr, strlen(addr)) < 0){ sysclose(fd); return -1; } sysseek(fd, 0, 0); n = sysread(fd, reply, sizeof(reply)-1); sysclose(fd); if(n <= 0) return -1; reply[n] = '\0'; /* * parse the reply */ cp = strchr(reply, ' '); if(cp == 0) return -1; *cp++ = 0; strncpy(naddr, cp, na); naddr[na-1] = 0; strncpy(file, reply, nf); file[nf-1] = 0; return 0; } int sysannounce(char *addr, char *dir) { char *cp; int ctl, n, m; char buf[3*NAMELEN]; char buf2[3*NAMELEN]; char netdir[2*NAMELEN]; char naddr[3*NAMELEN]; /* * translate the address */ if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0){ werrstr("can't translate address"); return -1; } /* * get a control channel */ ctl = sysopen(netdir, ORDWR); if(ctl<0){ werrstr("can't open control channel"); return -1; } cp = strrchr(netdir, '/'); *cp = 0; /* * find out which line we have */ n = sprint(buf, "%.*s/", 2*NAMELEN+1, netdir); m = sysread(ctl, &buf[n], sizeof(buf)-n-1); if(m <= 0) { sysclose(ctl); werrstr("can't read control file"); return -1; } buf[n+m] = 0; /* * make the call */ n = sprint(buf2, "announce %.*s", 2*NAMELEN, naddr); if(syswrite(ctl, buf2, n) != n) { sysclose(ctl); werrstr("announcement fails"); return -1; } strcpy(dir, buf); return ctl; } int syslisten(char *dir, char *newdir) { char *cp; int ctl, n, m; char buf[3*NAMELEN]; /* * open listen, wait for a call */ sprint(buf, "%.*s/listen", 2*NAMELEN+1, dir); ctl = sysopen(buf, ORDWR); if(ctl < 0) return -1; /* * find out which line we have */ strcpy(buf, dir); cp = strrchr(buf, '/'); *++cp = 0; n = cp-buf; m = sysread(ctl, cp, sizeof(buf) - n - 1); if(n<=0){ sysclose(ctl); return -1; } buf[n+m] = 0; strcpy(newdir, buf); return ctl; } drawterm-20170818/kern/sysfile.c000066400000000000000000000432131314554504700164070ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "user.h" #undef open #undef mount #undef read #undef write #undef seek #undef stat #undef wstat #undef remove #undef close #undef fstat #undef fwstat /* * The sys*() routines needn't poperror() as they return directly to syscall(). */ static void unlockfgrp(Fgrp *f) { int ex; ex = f->exceed; f->exceed = 0; unlock(&f->ref.lk); if(ex) pprint("warning: process exceeds %d file descriptors\n", ex); } int growfd(Fgrp *f, int fd) /* fd is always >= 0 */ { Chan **newfd, **oldfd; if(fd < f->nfd) return 0; if(fd >= f->nfd+DELTAFD) return -1; /* out of range */ /* * Unbounded allocation is unwise; besides, there are only 16 bits * of fid in 9P */ if(f->nfd >= 5000){ Exhausted: print("no free file descriptors\n"); return -1; } newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*)); if(newfd == 0) goto Exhausted; oldfd = f->fd; memmove(newfd, oldfd, f->nfd*sizeof(Chan*)); f->fd = newfd; free(oldfd); f->nfd += DELTAFD; if(fd > f->maxfd){ if(fd/100 > f->maxfd/100) f->exceed = (fd/100)*100; f->maxfd = fd; } return 1; } /* * this assumes that the fgrp is locked */ int findfreefd(Fgrp *f, int start) { int fd; for(fd=start; fdnfd; fd++) if(f->fd[fd] == 0) break; if(fd >= f->nfd && growfd(f, fd) < 0) return -1; return fd; } int newfd(Chan *c) { int fd; Fgrp *f; f = up->fgrp; lock(&f->ref.lk); fd = findfreefd(f, 0); if(fd < 0){ unlockfgrp(f); return -1; } if(fd > f->maxfd) f->maxfd = fd; f->fd[fd] = c; unlockfgrp(f); return fd; } int newfd2(int fd[2], Chan *c[2]) { Fgrp *f; f = up->fgrp; lock(&f->ref.lk); fd[0] = findfreefd(f, 0); if(fd[0] < 0){ unlockfgrp(f); return -1; } fd[1] = findfreefd(f, fd[0]+1); if(fd[1] < 0){ unlockfgrp(f); return -1; } if(fd[1] > f->maxfd) f->maxfd = fd[1]; f->fd[fd[0]] = c[0]; f->fd[fd[1]] = c[1]; unlockfgrp(f); return 0; } Chan* fdtochan(int fd, int mode, int chkmnt, int iref) { Chan *c; Fgrp *f; c = 0; f = up->fgrp; lock(&f->ref.lk); if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) { unlock(&f->ref.lk); error(Ebadfd); } if(iref) incref(&c->ref); unlock(&f->ref.lk); if(chkmnt && (c->flag&CMSG)) { if(iref) cclose(c); error(Ebadusefd); } if(mode<0 || c->mode==ORDWR) return c; if((mode&OTRUNC) && c->mode==OREAD) { if(iref) cclose(c); error(Ebadusefd); } if((mode&~OTRUNC) != c->mode) { if(iref) cclose(c); error(Ebadusefd); } return c; } int openmode(ulong o) { o &= ~(OTRUNC|OCEXEC|ORCLOSE); if(o > OEXEC) error(Ebadarg); if(o == OEXEC) return OREAD; return o; } long _sysfd2path(int fd, char *buf, uint nbuf) { Chan *c; c = fdtochan(fd, -1, 0, 1); if(c->name == nil) snprint(buf, nbuf, ""); else snprint(buf, nbuf, "%s", c->name->s); cclose(c); return 0; } long _syspipe(int fd[2]) { Chan *c[2]; Dev *d; static char *datastr[] = {"data", "data1"}; d = devtab[devno('|', 0)]; c[0] = namec("#|", Atodir, 0, 0); c[1] = 0; fd[0] = -1; fd[1] = -1; if(waserror()){ cclose(c[0]); if(c[1]) cclose(c[1]); nexterror(); } c[1] = cclone(c[0]); if(walk(&c[0], datastr+0, 1, 1, nil) < 0) error(Egreg); if(walk(&c[1], datastr+1, 1, 1, nil) < 0) error(Egreg); c[0] = d->open(c[0], ORDWR); c[1] = d->open(c[1], ORDWR); if(newfd2(fd, c) < 0) error(Enofd); poperror(); return 0; } long _sysdup(int fd0, int fd1) { int fd; Chan *c, *oc; Fgrp *f = up->fgrp; /* * Close after dup'ing, so date > #d/1 works */ c = fdtochan(fd0, -1, 0, 1); fd = fd1; if(fd != -1){ lock(&f->ref.lk); if(fd<0 || growfd(f, fd)<0) { unlockfgrp(f); cclose(c); error(Ebadfd); } if(fd > f->maxfd) f->maxfd = fd; oc = f->fd[fd]; f->fd[fd] = c; unlockfgrp(f); if(oc) cclose(oc); }else{ if(waserror()) { cclose(c); nexterror(); } fd = newfd(c); if(fd < 0) error(Enofd); poperror(); } return fd; } long _sysopen(char *name, int mode) { int fd; Chan *c = 0; openmode(mode); /* error check only */ if(waserror()){ if(c) cclose(c); nexterror(); } c = namec(name, Aopen, mode, 0); fd = newfd(c); if(fd < 0) error(Enofd); poperror(); return fd; } void fdclose(int fd, int flag) { int i; Chan *c; Fgrp *f = up->fgrp; lock(&f->ref.lk); c = f->fd[fd]; if(c == 0){ /* can happen for users with shared fd tables */ unlock(&f->ref.lk); return; } if(flag){ if(c==0 || !(c->flag&flag)){ unlock(&f->ref.lk); return; } } f->fd[fd] = 0; if(fd == f->maxfd) for(i=fd; --i>=0 && f->fd[i]==0; ) f->maxfd = i; unlock(&f->ref.lk); cclose(c); } long _sysclose(int fd) { fdtochan(fd, -1, 0, 0); fdclose(fd, 0); return 0; } long unionread(Chan *c, void *va, long n) { int i; long nr; Mhead *m; Mount *mount; qlock(&c->umqlock); m = c->umh; rlock(&m->lock); mount = m->mount; /* bring mount in sync with c->uri and c->umc */ for(i = 0; mount != nil && i < c->uri; i++) mount = mount->next; nr = 0; while(mount != nil) { /* Error causes component of union to be skipped */ if(mount->to && !waserror()) { if(c->umc == nil){ c->umc = cclone(mount->to); c->umc = devtab[c->umc->type]->open(c->umc, OREAD); } nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset); c->umc->offset += nr; poperror(); } if(nr > 0) break; /* Advance to next element */ c->uri++; if(c->umc) { cclose(c->umc); c->umc = nil; } mount = mount->next; } runlock(&m->lock); qunlock(&c->umqlock); return nr; } static long kread(int fd, void *buf, long n, vlong *offp) { int dir; Chan *c; vlong off; c = fdtochan(fd, OREAD, 1, 1); if(waserror()) { cclose(c); nexterror(); } dir = c->qid.type&QTDIR; /* * The offset is passed through on directories, normally. sysseek complains but * pread is used by servers and e.g. exportfs that shouldn't need to worry about this issue. */ if(offp == nil) /* use and maintain channel's offset */ off = c->offset; else off = *offp; if(off < 0) error(Enegoff); if(dir && c->umh) n = unionread(c, buf, n); else n = devtab[c->type]->read(c, buf, n, off); if(offp == nil){ lock(&c->ref.lk); c->offset += n; unlock(&c->ref.lk); } poperror(); cclose(c); return n; } /* name conflicts with netbsd long _sys_read(int fd, void *buf, long n) { return kread(fd, buf, n, nil); } */ long _syspread(int fd, void *buf, long n, vlong off) { if(off == ((uvlong) ~0)) return kread(fd, buf, n, nil); return kread(fd, buf, n, &off); } static long kwrite(int fd, void *buf, long nn, vlong *offp) { Chan *c; long m, n; vlong off; n = 0; c = fdtochan(fd, OWRITE, 1, 1); if(waserror()) { if(offp == nil){ lock(&c->ref.lk); c->offset -= n; unlock(&c->ref.lk); } cclose(c); nexterror(); } if(c->qid.type & QTDIR) error(Eisdir); n = nn; if(offp == nil){ /* use and maintain channel's offset */ lock(&c->ref.lk); off = c->offset; c->offset += n; unlock(&c->ref.lk); }else off = *offp; if(off < 0) error(Enegoff); m = devtab[c->type]->write(c, buf, n, off); if(offp == nil && m < n){ lock(&c->ref.lk); c->offset -= n - m; unlock(&c->ref.lk); } poperror(); cclose(c); return m; } long sys_write(int fd, void *buf, long n) { return kwrite(fd, buf, n, nil); } long _syspwrite(int fd, void *buf, long n, vlong off) { if(off == ((uvlong) ~0)) return kwrite(fd, buf, n, nil); return kwrite(fd, buf, n, &off); } static vlong _sysseek(int fd, vlong off, int whence) { Chan *c; uchar buf[sizeof(Dir)+100]; Dir dir; int n; c = fdtochan(fd, -1, 1, 1); if(waserror()){ cclose(c); nexterror(); } if(devtab[c->type]->dc == '|') error(Eisstream); switch(whence){ case 0: if((c->qid.type & QTDIR) && off != 0) error(Eisdir); if(off < 0) error(Enegoff); c->offset = off; break; case 1: if(c->qid.type & QTDIR) error(Eisdir); lock(&c->ref.lk); /* lock for read/write update */ off = off + c->offset; if(off < 0) error(Enegoff); c->offset = off; unlock(&c->ref.lk); break; case 2: if(c->qid.type & QTDIR) error(Eisdir); n = devtab[c->type]->stat(c, buf, sizeof buf); if(convM2D(buf, n, &dir, nil) == 0) error("internal error: stat error in seek"); off = dir.length + off; if(off < 0) error(Enegoff); c->offset = off; break; default: error(Ebadarg); } c->uri = 0; c->dri = 0; cclose(c); poperror(); return off; } void validstat(uchar *s, int n) { int m; char buf[64]; if(statcheck(s, n) < 0) error(Ebadstat); /* verify that name entry is acceptable */ s += STATFIXLEN - 4*BIT16SZ; /* location of first string */ /* * s now points at count for first string. * if it's too long, let the server decide; this is * only for his protection anyway. otherwise * we'd have to allocate and waserror. */ m = GBIT16(s); s += BIT16SZ; if(m+1 > sizeof buf) return; memmove(buf, s, m); buf[m] = '\0'; /* name could be '/' */ if(strcmp(buf, "/") != 0) validname(buf, 0); } long _sysfstat(int fd, void *buf, long n) { Chan *c; uint l; l = n; validaddr(buf, l, 1); c = fdtochan(fd, -1, 0, 1); if(waserror()) { cclose(c); nexterror(); } l = devtab[c->type]->stat(c, buf, l); poperror(); cclose(c); return l; } long _sysstat(char *name, void *buf, long n) { Chan *c; uint l; l = n; validaddr(buf, l, 1); validaddr(name, 1, 0); c = namec(name, Aaccess, 0, 0); if(waserror()){ cclose(c); nexterror(); } l = devtab[c->type]->stat(c, buf, l); poperror(); cclose(c); return l; } long _syschdir(char *name) { Chan *c; validaddr(name, 1, 0); c = namec(name, Atodir, 0, 0); cclose(up->dot); up->dot = c; return 0; } long bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec) { int ret; Chan *c0, *c1, *ac, *bc; struct{ Chan *chan; Chan *authchan; char *spec; int flags; }bogus; if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER)) error(Ebadarg); bogus.flags = flag & MCACHE; if(ismount){ if(up->pgrp->noattach) error(Enoattach); ac = nil; bc = fdtochan(fd, ORDWR, 0, 1); if(waserror()) { if(ac) cclose(ac); cclose(bc); nexterror(); } if(afd >= 0) ac = fdtochan(afd, ORDWR, 0, 1); bogus.chan = bc; bogus.authchan = ac; validaddr((ulong)spec, 1, 0); bogus.spec = spec; if(waserror()) error(Ebadspec); validname(spec, 1); poperror(); ret = devno('M', 0); c0 = devtab[ret]->attach((char*)&bogus); poperror(); if(ac) cclose(ac); cclose(bc); }else{ bogus.spec = 0; validaddr((ulong)arg0, 1, 0); c0 = namec(arg0, Abind, 0, 0); } if(waserror()){ cclose(c0); nexterror(); } validaddr((ulong)arg1, 1, 0); c1 = namec(arg1, Amount, 0, 0); if(waserror()){ cclose(c1); nexterror(); } ret = cmount(&c0, c1, flag, bogus.spec); poperror(); cclose(c1); poperror(); cclose(c0); if(ismount) fdclose(fd, 0); return ret; } long _sysbind(char *old, char *new, int flag) { return bindmount(0, -1, -1, old, new, flag, nil); } long _sysmount(int fd, int afd, char *new, int flag, char *spec) { return bindmount(1, fd, afd, nil, new, flag, spec); } long _sysunmount(char *old, char *new) { Chan *cmount, *cmounted; cmounted = 0; cmount = namec(new, Amount, 0, 0); if(old) { if(waserror()) { cclose(cmount); nexterror(); } validaddr(old, 1, 0); /* * This has to be namec(..., Aopen, ...) because * if arg[0] is something like /srv/cs or /fd/0, * opening it is the only way to get at the real * Chan underneath. */ cmounted = namec(old, Aopen, OREAD, 0); poperror(); } if(waserror()) { cclose(cmount); if(cmounted) cclose(cmounted); nexterror(); } cunmount(cmount, cmounted); cclose(cmount); if(cmounted) cclose(cmounted); poperror(); return 0; } long _syscreate(char *name, int mode, ulong perm) { int fd; Chan *c = 0; openmode(mode&~OEXCL); /* error check only; OEXCL okay here */ if(waserror()) { if(c) cclose(c); nexterror(); } validaddr(name, 1, 0); c = namec(name, Acreate, mode, perm); fd = newfd(c); if(fd < 0) error(Enofd); poperror(); return fd; } long _sysremove(char *name) { Chan *c; c = namec(name, Aremove, 0, 0); if(waserror()){ c->type = 0; /* see below */ cclose(c); nexterror(); } devtab[c->type]->remove(c); /* * Remove clunks the fid, but we need to recover the Chan * so fake it up. rootclose() is known to be a nop. */ c->type = 0; poperror(); cclose(c); return 0; } long _syswstat(char *name, void *buf, long n) { Chan *c; uint l; l = n; validstat(buf, l); validaddr(name, 1, 0); c = namec(name, Aaccess, 0, 0); if(waserror()){ cclose(c); nexterror(); } l = devtab[c->type]->wstat(c, buf, l); poperror(); cclose(c); return l; } long _sysfwstat(int fd, void *buf, long n) { Chan *c; uint l; l = n; validaddr(buf, l, 0); validstat(buf, l); c = fdtochan(fd, -1, 1, 1); if(waserror()) { cclose(c); nexterror(); } l = devtab[c->type]->wstat(c, buf, l); poperror(); cclose(c); return l; } static void starterror(void) { assert(up->nerrlab == 0); } static void _syserror(void) { char *p; p = up->syserrstr; up->syserrstr = up->errstr; up->errstr = p; } static void enderror(void) { assert(up->nerrlab == 1); poperror(); } int sysbind(char *old, char *new, int flag) { int n; starterror(); if(waserror()){ _syserror(); return -1; } n = _sysbind(old, new, flag); enderror(); return n; } int syschdir(char *path) { int n; starterror(); if(waserror()){ _syserror(); return -1; } n = _syschdir(path); enderror(); return n; } int sysclose(int fd) { int n; starterror(); if(waserror()){ _syserror(); return -1; } n = _sysclose(fd); enderror(); return n; } int syscreate(char *name, int mode, ulong perm) { int n; starterror(); if(waserror()){ _syserror(); return -1; } n = _syscreate(name, mode, perm); enderror(); return n; } int sysdup(int fd0, int fd1) { int n; starterror(); if(waserror()){ _syserror(); return -1; } n = _sysdup(fd0, fd1); enderror(); return n; } int sysfstat(int fd, uchar *buf, int n) { starterror(); if(waserror()){ _syserror(); return -1; } n = _sysfstat(fd, buf, n); enderror(); return n; } int sysfwstat(int fd, uchar *buf, int n) { starterror(); if(waserror()){ _syserror(); return -1; } n = _sysfwstat(fd, buf, n); enderror(); return n; } int sysmount(int fd, int afd, char *new, int flag, char *spec) { int n; starterror(); if(waserror()){ _syserror(); return -1; } n = _sysmount(fd, afd, new, flag, spec); enderror(); return n; } int sysunmount(char *old, char *new) { int n; starterror(); if(waserror()){ _syserror(); return -1; } n = _sysunmount(old, new); enderror(); return n; } int sysopen(char *name, int mode) { int n; starterror(); if(waserror()){ _syserror(); return -1; } n = _sysopen(name, mode); enderror(); return n; } int syspipe(int *fd) { int n; starterror(); if(waserror()){ _syserror(); return -1; } n = _syspipe(fd); enderror(); return n; } long syspread(int fd, void *buf, long n, vlong off) { starterror(); if(waserror()){ _syserror(); return -1; } n = _syspread(fd, buf, n, off); enderror(); return n; } long syspwrite(int fd, void *buf, long n, vlong off) { starterror(); if(waserror()){ _syserror(); return -1; } n = _syspwrite(fd, buf, n, off); enderror(); return n; } long sysread(int fd, void *buf, long n) { starterror(); if(waserror()){ _syserror(); return -1; } n = _syspread(fd, buf, n, (uvlong) ~0); enderror(); return n; } int sysremove(char *path) { int n; starterror(); if(waserror()){ _syserror(); return -1; } n = _sysremove(path); enderror(); return n; } vlong sysseek(int fd, vlong off, int whence) { starterror(); if(waserror()){ _syserror(); return -1; } off = _sysseek(fd, off, whence); enderror(); return off; } int sysstat(char *name, uchar *buf, int n) { starterror(); if(waserror()){ _syserror(); return -1; } n = _sysstat(name, buf, n); enderror(); return n; } long syswrite(int fd, void *buf, long n) { starterror(); if(waserror()){ _syserror(); return -1; } n = _syspwrite(fd, buf, n, (uvlong) ~0); enderror(); return n; } int syswstat(char *name, uchar *buf, int n) { starterror(); if(waserror()){ _syserror(); return -1; } n = _syswstat(name, buf, n); enderror(); return n; } void werrstr(char *f, ...) { char buf[ERRMAX]; va_list arg; va_start(arg, f); vsnprint(buf, sizeof buf, f, arg); va_end(arg); if(up->nerrlab) strecpy(up->errstr, up->errstr+ERRMAX, buf); else strecpy(up->syserrstr, up->syserrstr+ERRMAX, buf); } int __errfmt(Fmt *fmt) { if(up->nerrlab) return fmtstrcpy(fmt, up->errstr); else return fmtstrcpy(fmt, up->syserrstr); } int errstr(char *buf, uint n) { char tmp[ERRMAX]; char *p; p = up->nerrlab ? up->errstr : up->syserrstr; memmove(tmp, p, ERRMAX); utfecpy(p, p+ERRMAX, buf); utfecpy(buf, buf+n, tmp); return strlen(buf); } int rerrstr(char *buf, uint n) { char *p; p = up->nerrlab ? up->errstr : up->syserrstr; utfecpy(buf, buf+n, p); return strlen(buf); } void* _sysrendezvous(void* arg0, void* arg1) { void *tag, *val; Proc *p, **l; tag = arg0; l = &REND(up->rgrp, (uintptr)tag); up->rendval = (void*)~0; lock(&up->rgrp->ref.lk); for(p = *l; p; p = p->rendhash) { if(p->rendtag == tag) { *l = p->rendhash; val = p->rendval; p->rendval = arg1; while(p->mach != 0) ; procwakeup(p); unlock(&up->rgrp->ref.lk); return val; } l = &p->rendhash; } /* Going to sleep here */ up->rendtag = tag; up->rendval = arg1; up->rendhash = *l; *l = up; up->state = Rendezvous; unlock(&up->rgrp->ref.lk); procsleep(); return up->rendval; } void* sysrendezvous(void *tag, void *val) { void *n; starterror(); if(waserror()){ _syserror(); return (void*)~0; } n = _sysrendezvous(tag, val); enderror(); return n; } drawterm-20170818/kern/sysproc.c000066400000000000000000000007661314554504700164410ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" long sysexits(uintptr_t *arg) { char *status; char *inval = "invalid exit string"; char buf[ERRMAX]; status = (char*)arg[0]; if(status){ if(waserror()) status = inval; else{ validaddr((ulong)status, 1, 0); if(vmemchr(status, 0, ERRMAX) == 0){ memmove(buf, status, ERRMAX); buf[ERRMAX-1] = 0; status = buf; } } poperror(); } pexit(status, 1); return 0; /* not reached */ } drawterm-20170818/kern/term.c000066400000000000000000000075711314554504700157070ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include #include #include "screen.h" #define MINX 8 #define Backgnd 0xFF /* white */ Memsubfont *memdefont; struct{ Point pos; int bwid; }out; Lock screenlock; Memimage *conscol; Memimage *back; extern Memimage *gscreen; static Rectangle flushr; static Rectangle window; static Point curpos; static int h; static void termscreenputs(char*, int); static void screenflush(void) { drawflushr(flushr); flushr = Rect(10000, 10000, -10000, -10000); } static void addflush(Rectangle r) { if(flushr.min.x >= flushr.max.x) flushr = r; else combinerect(&flushr, r); } static void screenwin(void) { Point p; char *greet; Memimage *grey; drawqlock(); back = memwhite; conscol = memblack; memfillcolor(gscreen, 0x444488FF); h = memdefont->height; window.min = addpt(gscreen->r.min, Pt(20,20)); window.max.x = window.min.x + Dx(gscreen->r)*3/4-40; window.max.y = window.min.y + Dy(gscreen->r)*3/4-100; memimagedraw(gscreen, window, memblack, ZP, memopaque, ZP, S); window = insetrect(window, 4); memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S); /* a lot of work to get a grey color */ grey = allocmemimage(Rect(0,0,1,1), CMAP8); grey->flags |= Frepl; grey->clipr = gscreen->r; memfillcolor(grey, 0xAAAAAAFF); memimagedraw(gscreen, Rect(window.min.x, window.min.y, window.max.x, window.min.y+h+5+6), grey, ZP, nil, ZP, S); freememimage(grey); window = insetrect(window, 5); greet = " Plan 9 Console "; p = addpt(window.min, Pt(10, 0)); memimagestring(gscreen, p, conscol, ZP, memdefont, greet); window.min.y += h+6; curpos = window.min; window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h; flushmemscreen(gscreen->r); drawqunlock(); } void terminit(void) { memdefont = getmemdefont(); out.pos.x = MINX; out.pos.y = 0; out.bwid = memdefont->info[' '].width; screenwin(); screenputs = termscreenputs; } static void scroll(void) { int o; Point p; Rectangle r; o = 8*h; r = Rpt(window.min, Pt(window.max.x, window.max.y-o)); p = Pt(window.min.x, window.min.y+o); memimagedraw(gscreen, r, gscreen, p, nil, p, S); r = Rpt(Pt(window.min.x, window.max.y-o), window.max); memimagedraw(gscreen, r, back, ZP, nil, ZP, S); flushmemscreen(gscreen->r); curpos.y -= o; } static void screenputc(char *buf) { Point p; int w, pos; Rectangle r; static int *xp; static int xbuf[256]; if(xp < xbuf || xp >= &xbuf[nelem(xbuf)]) xp = xbuf; switch(buf[0]) { case '\n': if(curpos.y+h >= window.max.y) scroll(); curpos.y += h; screenputc("\r"); break; case '\r': xp = xbuf; curpos.x = window.min.x; break; case '\t': p = memsubfontwidth(memdefont, " "); w = p.x; *xp++ = curpos.x; pos = (curpos.x-window.min.x)/w; pos = 8-(pos%8); r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h); memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S); addflush(r); curpos.x += pos*w; break; case '\b': if(xp <= xbuf) break; xp--; r = Rect(*xp, curpos.y, curpos.x, curpos.y + h); memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S); addflush(r); curpos.x = *xp; break; default: p = memsubfontwidth(memdefont, buf); w = p.x; if(curpos.x >= window.max.x-w) screenputc("\n"); *xp++ = curpos.x; r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y + h); memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S); memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf); addflush(r); curpos.x += w; } } static void termscreenputs(char *s, int n) { int i, locked; Rune r; char buf[4]; lock(&screenlock); locked = drawcanqlock(); while(n > 0){ i = chartorune(&r, s); if(i == 0){ s++; --n; continue; } memmove(buf, s, i); buf[i] = 0; n -= i; s += i; screenputc(buf); } if(locked) drawqunlock(); screenflush(); unlock(&screenlock); } drawterm-20170818/kern/uart.c000066400000000000000000000002621314554504700157010ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" extern int panicking; void uartputs(char *s, int n) { if(panicking) write(1, s, n); } drawterm-20170818/kern/waserror.c000066400000000000000000000005761314554504700166020ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" Label* pwaserror(void) { if(up->nerrlab == NERR) panic("error stack overflow"); return &up->errlab[up->nerrlab++]; } void nexterror(void) { longjmp(up->errlab[--up->nerrlab].buf, 1); } void error(char *e) { kstrcpy(up->errstr, e, ERRMAX); setjmp(up->errlab[NERR-1].buf); nexterror(); } drawterm-20170818/kern/win32.c000066400000000000000000000200611314554504700156670ustar00rootroot00000000000000#include #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include typedef struct Oproc Oproc; struct Oproc { int tid; HANDLE *sema; }; static int tlsx = TLS_OUT_OF_INDEXES; char *argv0; Proc* _getproc(void) { if(tlsx == TLS_OUT_OF_INDEXES) return nil; return TlsGetValue(tlsx); } void _setproc(Proc *p) { if(tlsx == TLS_OUT_OF_INDEXES){ tlsx = TlsAlloc(); if(tlsx == TLS_OUT_OF_INDEXES) panic("out of indexes"); } TlsSetValue(tlsx, p); } void oserror(void) { oserrstr(); nexterror(); } void osinit(void) { Oproc *t; static Proc firstprocCTstore; _setproc(&firstprocCTstore); t = (Oproc*)firstprocCTstore.oproc; assert(t != 0); t->tid = GetCurrentThreadId(); t->sema = CreateSemaphore(0, 0, 1000, 0); if(t->sema == 0) { oserror(); panic("could not create semaphore: %r"); } } void osnewproc(Proc *p) { Oproc *op; op = (Oproc*)p->oproc; op->sema = CreateSemaphore(0, 0, 1000, 0); if (op->sema == 0) { oserror(); panic("could not create semaphore: %r"); } } void osmsleep(int ms) { Sleep((DWORD) ms); } void osyield(void) { Sleep(0); } static DWORD WINAPI tramp(LPVOID vp); void osproc(Proc *p) { DWORD tid; if(CreateThread(0, 0, tramp, p, 0, &tid) == 0) { oserror(); panic("osproc: %r"); } Sleep(0); } static DWORD WINAPI tramp(LPVOID vp) { Proc *p = (Proc *) vp; Oproc *op = (Oproc*) p->oproc; _setproc(p); op->tid = GetCurrentThreadId(); op->sema = CreateSemaphore(0, 0, 1000, 0); if(op->sema == 0) { oserror(); panic("could not create semaphore: %r"); } (*p->fn)(p->arg); ExitThread(0); return 0; } void procsleep(void) { Proc *p; Oproc *op; p = up; op = (Oproc*)p->oproc; WaitForSingleObject(op->sema, INFINITE);} void procwakeup(Proc *p) { Oproc *op; op = (Oproc*)p->oproc; ReleaseSemaphore(op->sema, 1, 0); } void random20(uchar *p) { LARGE_INTEGER ti; int i, j; FILETIME ft; DigestState ds; vlong tsc; GetSystemTimeAsFileTime(&ft); memset(&ds, 0, sizeof ds); sha1((uchar*)&ft, sizeof(ft), 0, &ds); for(i=0; i<50; i++) { for(j=0; j<10; j++) { QueryPerformanceCounter(&ti); sha1((uchar*)&ti, sizeof(ti), 0, &ds); tsc = GetTickCount(); sha1((uchar*)&tsc, sizeof(tsc), 0, &ds); } Sleep(10); } sha1(0, 0, p, &ds); } void randominit(void) { } ulong randomread(void *v, ulong n) { int i; uchar p[20]; for(i=0; i N backslashes and end quote * 2N+1 backslashes + " ==> N backslashes + literal " * N backslashes not followed by " ==> N backslashes */ static int args(char *argv[], int n, char *p) { char *p2; int i, j, quote, nbs; for(i=0; *p && i>1); j++) *p2++ = '\\'; if(nbs&1) *p2++ = *p; else quote = !quote; } else { for(j=0; jerrstr, ERRMAX); } long showfilewrite(char *a, int n) { Rune *action, *arg, *cmd, *p; static Rune Lopen[] = { 'o', 'p', 'e', 'n', 0 }; cmd = runesmprint("%.*s", n, a); if(cmd == nil) error("out of memory"); if(cmd[runestrlen(cmd)-1] == '\n') cmd[runestrlen(cmd)] = 0; p = runestrchr(cmd, ' '); if(p){ action = cmd; *p++ = 0; arg = p; }else{ action = Lopen; arg = cmd; } ShellExecute(0, 0, action, arg, 0, SW_SHOWNORMAL); return n; } drawterm-20170818/kern/x000066400000000000000000000215211314554504700147550ustar00rootroot00000000000000#include #include #include #include #include #include /* for remove, rename */ #include #ifndef NAME_MAX # define NAME_MAX 256 #endif #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" typedef struct Ufsinfo Ufsinfo; enum { NUID = 256, NGID = 256, MAXPATH = 1024, MAXCOMP = 128 }; struct Ufsinfo { int mode; int fd; DIR* dir; ulong offset; QLock oq; char nextname[NAME_MAX]; }; char *base = "/"; static Qid fsqid(char*, struct stat *); static void fspath(Chan*, char*, char*); static ulong fsdirread(Chan*, uchar*, int, ulong); static int fsomode(int); static char* lastelem(Chan *c) { char *s, *t; s = c2name(c); if((t = strrchr(s, '/')) == nil) return s; if(t[1] == 0) return t; return t+1; } static Chan* fsattach(char *spec) { Chan *c; struct stat stbuf; static int devno; Ufsinfo *uif; if(stat(base, &stbuf) < 0) error(strerror(errno)); c = devattach('U', spec); uif = mallocz(sizeof(Ufsinfo), 1); uif->mode = stbuf.st_mode; c->aux = uif; c->dev = devno++; return c; } static Chan* fsclone(Chan *c, Chan *nc) { Ufsinfo *uif; uif = mallocz(sizeof(Ufsinfo), 1); *uif = *(Ufsinfo*)c->aux; nc->aux = uif; return nc; } static int fswalk1(Chan *c, char *name) { struct stat stbuf; char path[MAXPATH]; Ufsinfo *uif; fspath(c, name, path); /* print("** fs walk '%s' -> %s\n", path, name); */ if(stat(path, &stbuf) < 0) return 0; uif = c->aux; uif->mode = stbuf.st_mode; c->qid = fsqid(path, &stbuf); return 1; } static Walkqid* fswalk(Chan *c, Chan *nc, char **name, int nname) { int i; Walkqid *wq; if(nc != nil) panic("fswalk: nc != nil"); wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); nc = devclone(c); fsclone(c, nc); wq->clone = nc; for(i=0; iqid[i] = nc->qid; } if(i != nname){ cclose(nc); wq->clone = nil; } wq->nqid = i; return wq; } static int fsstat(Chan *c, uchar *buf, int n) { Dir d; struct stat stbuf; char path[MAXPATH]; if(n < BIT16SZ) error(Eshortstat); fspath(c, 0, path); if(stat(path, &stbuf) < 0) error(strerror(errno)); d.name = lastelem(c); d.uid = "unknown"; d.gid = "unknown"; d.qid = c->qid; d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777); d.atime = stbuf.st_atime; d.mtime = stbuf.st_mtime; d.length = stbuf.st_size; d.type = 'U'; d.dev = c->dev; return convD2M(&d, buf, n); } static Chan* fsopen(Chan *c, int mode) { char path[MAXPATH]; int m, isdir; Ufsinfo *uif; m = mode & (OTRUNC|3); switch(m) { case 0: break; case 1: case 1|16: break; case 2: case 0|16: case 2|16: break; case 3: break; default: error(Ebadarg); } isdir = c->qid.type & QTDIR; if(isdir && mode != OREAD) error(Eperm); m = fsomode(m & 3); c->mode = openmode(mode); uif = c->aux; fspath(c, 0, path); if(isdir) { uif->dir = opendir(path); if(uif->dir == 0) error(strerror(errno)); } else { if(mode & OTRUNC) m |= O_TRUNC; uif->fd = open(path, m, 0666); if(uif->fd < 0) error(strerror(errno)); } uif->offset = 0; c->offset = 0; c->flag |= COPEN; return c; } static void fscreate(Chan *c, char *name, int mode, ulong perm) { int fd, m; char path[MAXPATH]; struct stat stbuf; Ufsinfo *uif; m = fsomode(mode&3); fspath(c, name, path); uif = c->aux; if(perm & DMDIR) { if(m) error(Eperm); if(mkdir(path, perm & 0777) < 0) error(strerror(errno)); fd = open(path, 0); if(fd >= 0) { chmod(path, perm & 0777); chown(path, uif->uid, uif->uid); } close(fd); uif->dir = opendir(path); if(uif->dir == 0) error(strerror(errno)); } else { fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666); if(fd >= 0) { if(m != 1) { close(fd); fd = open(path, m); } chmod(path, perm & 0777); chown(path, uif->uid, uif->gid); } if(fd < 0) error(strerror(errno)); uif->fd = fd; } if(stat(path, &stbuf) < 0) error(strerror(errno)); c->qid = fsqid(path, &stbuf); c->offset = 0; c->flag |= COPEN; c->mode = openmode(mode); } static void fsclose(Chan *c) { Ufsinfo *uif; uif = c->aux; if(c->flag & COPEN) { if(c->qid.type & QTDIR) closedir(uif->dir); else close(uif->fd); } free(uif); } static long fsread(Chan *c, void *va, long n, vlong offset) { int fd, r; Ufsinfo *uif; if(c->qid.type & QTDIR) return fsdirread(c, va, n, offset); uif = c->aux; qlock(&uif->oq); if(waserror()) { qunlock(&uif->oq); nexterror(); } fd = uif->fd; if(uif->offset != offset) { r = lseek(fd, offset, 0); if(r < 0) error(strerror(errno)); uif->offset = offset; } n = read(fd, va, n); if(n < 0) error(strerror(errno)); uif->offset += n; qunlock(&uif->oq); poperror(); return n; } static long fswrite(Chan *c, void *va, long n, vlong offset) { int fd, r; Ufsinfo *uif; uif = c->aux; qlock(&uif->oq); if(waserror()) { qunlock(&uif->oq); nexterror(); } fd = uif->fd; if(uif->offset != offset) { r = lseek(fd, offset, 0); if(r < 0) error(strerror(errno)); uif->offset = offset; } n = write(fd, va, n); if(n < 0) error(strerror(errno)); uif->offset += n; qunlock(&uif->oq); poperror(); return n; } static void fsremove(Chan *c) { int n; char path[MAXPATH]; fspath(c, 0, path); if(c->qid.type & QTDIR) n = rmdir(path); else n = remove(path); if(n < 0) error(strerror(errno)); } void fswstat(Chan *c, uchar *buf, int n) { Dir d; struct stat stbuf; char old[MAXPATH], new[MAXPATH], dir[MAXPATH]; char strs[MAXPATH*3]; Ufsinfo *uif; if(convM2D(buf, n, &d, strs) != n) error(Ebadstat); fspath(c, 0, old); if(stat(old, &stbuf) < 0) error(strerror(errno)); uif = c->aux; if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) { fspath(c->parent, 0, dir); fspath(c, 0, old); strcpy(new, old); p = strrchr(new, '/'); strcpy(p+1, d.name); if(rename(old, new) < 0) error(strerror(errno)); } fspath(c, 0, old); if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) { if(chmod(old, d.mode&0777) < 0) error(strerror(errno)); uif->mode &= ~0777; uif->mode |= d.mode&0777; } /* p = name2pass(gid, d.gid); if(p == 0) error(Eunknown); if(p->id != stbuf.st_gid) { if(chown(old, stbuf.st_uid, p->id) < 0) error(strerror(errno)); uif->gid = p->id; } */ } static Qid fsqid(char *p, struct stat *st) { Qid q; int dev; ulong h; static int nqdev; static uchar *qdev; if(qdev == 0) qdev = mallocz(65536U, 1); q.type = 0; if((st->st_mode&S_IFMT) == S_IFDIR) q.type = QTDIR; dev = st->st_dev & 0xFFFFUL; if(qdev[dev] == 0) qdev[dev] = ++nqdev; h = 0; while(*p != '\0') h += *p++ * 13; q.path = (vlong)qdev[dev]<<32; q.path |= h; q.vers = st->st_mtime; return q; } static void fspath(Chan *c, char *ext, char *path) { int i, n; char *comp[MAXCOMP]; strcpy(path, base); strcat(path, "/"); strcat(path, c2name(c)); if(ext){ strcat(path, "/"); strcat(path, ext); } cleanname(path); } static int isdots(char *name) { if(name[0] != '.') return 0; if(name[1] == '\0') return 1; if(name[1] != '.') return 0; if(name[2] == '\0') return 1; return 0; } static int p9readdir(char *name, Ufsinfo *uif) { struct dirent *de; if(uif->nextname[0]){ strcpy(name, uif->nextname); uif->nextname[0] = 0; return 1; } de = readdir(uif->dir); if(de == NULL) return 0; strcpy(name, de->d_name); return 1; } static ulong fsdirread(Chan *c, uchar *va, int count, ulong offset) { int i; Dir d; long n; char de[NAME_MAX]; struct stat stbuf; char path[MAXPATH], dirpath[MAXPATH]; Ufsinfo *uif; int n; i = 0; uif = c->aux; errno = 0; if(uif->offset != offset) { if(offset != 0) error("bad offset in fsdirread"); uif->offset = offset; /* sync offset */ uif->nextname[0] = 0; rewinddir(uif->dir); } fspath(c, 0, dirpath); while(i+BIT16SZ < count) { if(!p9readdir(de, uif)) break; if(de[0]==0 || isdots(de)) continue; d.name = de; sprint(path, "%s/%s", dirpath, de); memset(&stbuf, 0, sizeof stbuf); if(stat(path, &stbuf) < 0) { fprint(2, "dir: bad path %s\n", path); /* but continue... probably a bad symlink */ } d.uid = "unknown"; d.gid = "unknown"; d.qid = fsqid(path, &stbuf); d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777); d.atime = stbuf.st_atime; d.mtime = stbuf.st_mtime; d.length = stbuf.st_size; d.type = 'U'; d.dev = c->dev; n = convD2M(&d, (char*)va+i, count-i); if(n == BIT16SZ){ strcpy(uif->nextname, de); break; } i += n; } return i; } static int fsomode(int m) { switch(m) { case 0: /* OREAD */ case 3: /* OEXEC */ return 0; case 1: /* OWRITE */ return 1; case 2: /* ORDWR */ return 2; } error(Ebadarg); return 0; } Dev fsdevtab = { 'U', "fs", devreset, devinit, devshutdown, fsattach, fswalk, fsstat, fsopen, fscreate, fsclose, fsread, devbread, fswrite, devbwrite, fsremove, fswstat, }; drawterm-20170818/latin1.c000066400000000000000000000171761314554504700151730ustar00rootroot00000000000000#include "u.h" #include "libc.h" /* * The code makes two assumptions: strlen(ld) is 1 or 2; latintab[i].ld can be a * prefix of latintab[j].ld only when j", { 0x21D2, 0x2255, 0x2261, 0x229C, 0x22DC, 0x22DD, }, "V", "=", { 0x21D0, }, "7", "8", { 0x215E, }, "5", "68", { 0x215A, 0x215D, }, "4", "5", { 0x2158, }, "R", "R", { 0x211D, }, "Q", "Q", { 0x211A, }, "P", "P", { 0x2119, }, "C", "CAU", { 0x2102, 0x22C2, 0x22C3, }, "e", "nmsl", { 0x2013, 0x2014, 0x2205, 0x22EF, }, "b", "u0123456789+-=()kqrbnp", { 0x2022, 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x265A, 0x265B, 0x265C, 0x265D, 0x265E, 0x265F, }, "@e", "h", { 0x44D, }, "@\'", "\'", { 0x44A, }, "@s", "hc", { 0x448, 0x449, }, "@c", "h", { 0x447, }, "@t", "s", { 0x446, }, "@k", "h", { 0x445, }, "@z", "h", { 0x436, }, "@y", "euao", { 0x435, 0x44E, 0x44F, 0x451, }, "@E", "Hh", { 0x42D, 0x42D, }, "@S", "HhCc", { 0x428, 0x428, 0x429, 0x429, }, "@C", "Hh", { 0x427, 0x427, }, "@T", "Ss", { 0x426, 0x426, }, "@K", "Hh", { 0x425, 0x425, }, "@Z", "Hh", { 0x416, 0x416, }, "@@", "EZKSTYezksty\'", { 0x415, 0x417, 0x41A, 0x421, 0x422, 0x42B, 0x435, 0x437, 0x43A, 0x441, 0x442, 0x44B, 0x44C, }, "@Y", "OoEeUuAa", { 0x401, 0x401, 0x415, 0x415, 0x42E, 0x42E, 0x42F, 0x42F, }, "@", "ABVGDIJLMNOPRUFXabvgdijlmnoprufx", { 0x410, 0x411, 0x412, 0x413, 0x414, 0x418, 0x419, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420, 0x423, 0x424, 0x425, 0x430, 0x431, 0x432, 0x433, 0x434, 0x438, 0x439, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x443, 0x444, 0x445, }, "*", "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw*", { 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4, 0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x2217, }, "G", "-", { 0x1E4, }, "N", "JjN", { 0x1CA, 0x1CB, 0x2115, }, "2", "-35", { 0x1BB, 0x2154, 0x2156, }, "z", "-", { 0x1B6, }, "Z", "-Z", { 0x1B5, 0x2124, }, "Y", "R", { 0x1A6, }, "h", "v-", { 0x195, 0x210F, }, "$*", "hfk", { 0x3D1, 0x3D5, 0x3F0, }, "$", "fVavgHILlpRBeEFMo", { 0x192, 0x1B2, 0x251, 0x28B, 0x210A, 0x210B, 0x2110, 0x2112, 0x2113, 0x2118, 0x211B, 0x212C, 0x212F, 0x2130, 0x2131, 0x2133, 0x2134, }, "t", "-smefu", { 0x167, 0x3C2, 0x2122, 0x2203, 0x2234, 0x22A2, }, "T", "-u", { 0x166, 0x22A8, }, "L", "-Jj&|", { 0x141, 0x1C7, 0x1C8, 0x22C0, 0x22C1, }, "i", "j-fsbp", { 0x133, 0x268, 0x221E, 0x222B, 0x2286, 0x2287, }, "I", "J-", { 0x132, 0x197, }, "H", "-H", { 0x126, 0x210D, }, "v\"", "Uu", { 0x1D9, 0x1DA, }, "v", "CcDdEeLlNnRrSsTtZzAaIiOoUuGgKkj", { 0x10C, 0x10D, 0x10E, 0x10F, 0x11A, 0x11B, 0x13D, 0x13E, 0x147, 0x148, 0x158, 0x159, 0x160, 0x161, 0x164, 0x165, 0x17D, 0x17E, 0x1CD, 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4, 0x1E6, 0x1E7, 0x1E8, 0x1E9, 0x1F0, }, "u", "AEeGgIiOoUu-a", { 0x102, 0x114, 0x115, 0x11E, 0x11F, 0x12C, 0x12D, 0x14E, 0x14F, 0x16C, 0x16D, 0x289, 0x2191, }, ":", "-=()", { 0xF7, 0x2254, 0x2639, 0x263A, }, "a", "ebn", { 0xE6, 0x2194, 0x2220, }, "/", "Oo", { 0xD8, 0xF8, }, "Dv", "Zz", { 0x1C4, 0x1C5, }, "D", "-e", { 0xD0, 0x2206, }, "A", "E", { 0xC6, }, "o", "AaeUuiO", { 0xC5, 0xE5, 0x153, 0x16E, 0x16F, 0x1A3, 0x229A, }, "~!", "=", { 0x2246, }, "~", "ANOanoIiUu-=~", { 0xC3, 0xD1, 0xD5, 0xE3, 0xF1, 0xF5, 0x128, 0x129, 0x168, 0x169, 0x2243, 0x2245, 0x2248, }, "^", "AEIOUaeiouCcGgHhJjSsWwYy", { 0xC2, 0xCA, 0xCE, 0xD4, 0xDB, 0xE2, 0xEA, 0xEE, 0xF4, 0xFB, 0x108, 0x109, 0x11C, 0x11D, 0x124, 0x125, 0x134, 0x135, 0x15C, 0x15D, 0x174, 0x175, 0x176, 0x177, }, "`\"", "Uu", { 0x1DB, 0x1DC, }, "`", "AEIOUaeiou", { 0xC0, 0xC8, 0xCC, 0xD2, 0xD9, 0xE0, 0xE8, 0xEC, 0xF2, 0xF9, }, "?", "?!", { 0xBF, 0x203D, }, "3", "458", { 0xBE, 0x2157, 0x215C, }, "1", "423568", { 0xBC, 0xBD, 0x2153, 0x2155, 0x2159, 0x215B, }, ">!", "=~", { 0x2269, 0x22E7, }, ">", ">=~<", { 0xBB, 0x2265, 0x2273, 0x2277, }, ",", ",CcAaEeGgIiKkLlNnRrSsTtUuOo", { 0xB8, 0xC7, 0xE7, 0x104, 0x105, 0x118, 0x119, 0x122, 0x123, 0x12E, 0x12F, 0x136, 0x137, 0x13B, 0x13C, 0x145, 0x146, 0x156, 0x157, 0x15E, 0x15F, 0x162, 0x163, 0x172, 0x173, 0x1EA, 0x1EB, }, ".", ".CcEeGgILlZzO", { 0xB7, 0x10A, 0x10B, 0x116, 0x117, 0x120, 0x121, 0x130, 0x13F, 0x140, 0x17B, 0x17C, 0x2299, }, "p", "gOdrt", { 0xB6, 0x2117, 0x2202, 0x220F, 0x221D, }, "m", "iuo", { 0xB5, 0xD7, 0x2208, }, "\'\"", "Uu", { 0x1D7, 0x1D8, }, "\'", "\'AEIOUYaeiouyCcgLlNnRrSsZz", { 0xB4, 0xC1, 0xC9, 0xCD, 0xD3, 0xDA, 0xDD, 0xE1, 0xE9, 0xED, 0xF3, 0xFA, 0xFD, 0x106, 0x107, 0x123, 0x139, 0x13A, 0x143, 0x144, 0x154, 0x155, 0x15A, 0x15B, 0x179, 0x17A, }, "+", "-O", { 0xB1, 0x2295, }, "dv", "z", { 0x1C6, }, "d", "e-zgda", { 0xB0, 0xF0, 0x2A3, 0x2020, 0x2021, 0x2193, }, "_,", "Oo", { 0x1EC, 0x1ED, }, "_.", "Aa", { 0x1E0, 0x1E1, }, "_\"", "UuAa", { 0x1D5, 0x1D6, 0x1DE, 0x1DF, }, "_", "_AaEeIiOoUu", { 0xAF, 0x100, 0x101, 0x112, 0x113, 0x12A, 0x12B, 0x14C, 0x14D, 0x16A, 0x16B, }, "r", "O\'\"", { 0xAE, 0x2019, 0x201D, }, "-*", "l", { 0x19B, }, "-", "-Dd:HLlTtbIZz2Ggiuh>+~O", { 0xAD, 0xD0, 0xF0, 0xF7, 0x126, 0x141, 0x142, 0x166, 0x167, 0x180, 0x197, 0x1B5, 0x1B6, 0x1BB, 0x1E4, 0x1E5, 0x268, 0x289, 0x210F, 0x2192, 0x2213, 0x2242, 0x2296, }, "n", "oj", { 0xAC, 0x1CC, }, "", { 0xAB, 0x2190, 0x2264, 0x2272, 0x2276, }, "s", "a231os0456789+-=()nturbp", { 0xAA, 0xB2, 0xB3, 0xB9, 0xBA, 0xDF, 0x2070, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F, 0x220D, 0x2211, 0x221A, 0x2282, 0x2283, }, "O", "crEIp+-x/.o*=", { 0xA9, 0xAE, 0x152, 0x1A2, 0x2117, 0x2295, 0x2296, 0x2297, 0x2298, 0x2299, 0x229A, 0x229B, 0x229C, }, "\"*", "IUiu", { 0x3AA, 0x3AB, 0x3CA, 0x3CB, }, "\"", "\"AEIOUaeiouyY", { 0xA8, 0xC4, 0xCB, 0xCF, 0xD6, 0xDC, 0xE4, 0xEB, 0xEF, 0xF6, 0xFC, 0xFF, 0x178, }, "S", "S", { 0xA7, }, "|", "|Pp", { 0xA6, 0xDE, 0xFE, }, "y", "$", { 0xA5, }, "g", "$-r", { 0xA4, 0x1E5, 0x2207, }, "l", "$-j\'\"&|z", { 0xA3, 0x142, 0x1C9, 0x2018, 0x201C, 0x2227, 0x2228, 0x22C4, }, "c", "$Oaug", { 0xA2, 0xA9, 0x2229, 0x222A, 0x2245, }, "!~", "-=~", { 0x2244, 0x2247, 0x2249, }, "!", "!?m=<>bp", { 0xA1, 0x203D, 0x2209, 0x2260, 0x226E, 0x226F, 0x2284, 0x2285, }, 0, 0, { 0, } }; /* * Given 5 characters k[0]..k[4], find the rune or return -1 for failure. */ long unicode(Rune *k) { long i, c; k++; /* skip 'X' */ c = 0; for(i=0; i<4; i++,k++){ c <<= 4; if('0'<=*k && *k<='9') c += *k-'0'; else if('a'<=*k && *k<='f') c += 10 + *k-'a'; else if('A'<=*k && *k<='F') c += 10 + *k-'A'; else return -1; } return c; } /* * Given n characters k[0]..k[n-1], find the corresponding rune or return -1 for * failure, or something < -1 if n is too small. In the latter case, the result * is minus the required n. */ long latin1(Rune *k, int n) { struct cvlist *l; int c; char* p; if(k[0] == 'X'){ if(n>=5) return unicode(k); else return -5; } for(l=latintab; l->ld!=0; l++) if(k[0] == l->ld[0]){ if(n == 1) return -2; if(l->ld[1] == 0) c = k[1]; else if(l->ld[1] != k[1]) continue; else if(n == 2) return -3; else c = k[2]; for(p=l->si; *p!=0; p++) if(*p == c) return l->so[p - l->si]; return -1; } return -1; } drawterm-20170818/lib/000077500000000000000000000000001314554504700143715ustar00rootroot00000000000000drawterm-20170818/lib/codereview/000077500000000000000000000000001314554504700165255ustar00rootroot00000000000000drawterm-20170818/lib/codereview/codereview.cfg000066400000000000000000000000541314554504700213410ustar00rootroot00000000000000# defaultcc: plan9port-dev@googlegroups.com drawterm-20170818/lib/codereview/codereview.py000066400000000000000000003200131314554504700212320ustar00rootroot00000000000000# coding=utf-8 # (The line above is necessary so that I can use 世界 in the # *comment* below without Python getting all bent out of shape.) # Copyright 2007-2009 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. '''Mercurial interface to codereview.appspot.com. To configure, set the following options in your repository's .hg/hgrc file. [extensions] codereview = /path/to/codereview.py [codereview] server = codereview.appspot.com The server should be running Rietveld; see http://code.google.com/p/rietveld/. In addition to the new commands, this extension introduces the file pattern syntax @nnnnnn, where nnnnnn is a change list number, to mean the files included in that change list, which must be associated with the current client. For example, if change 123456 contains the files x.go and y.go, "hg diff @123456" is equivalent to"hg diff x.go y.go". ''' import sys if __name__ == "__main__": print >>sys.stderr, "This is a Mercurial extension and should not be invoked directly." sys.exit(2) # We require Python 2.6 for the json package. if sys.version < '2.6': print >>sys.stderr, "The codereview extension requires Python 2.6 or newer." print >>sys.stderr, "You are running Python " + sys.version sys.exit(2) import json import os import re import stat import subprocess import threading import time from mercurial import commands as hg_commands from mercurial import util as hg_util defaultcc = None codereview_disabled = None real_rollback = None releaseBranch = None server = "codereview.appspot.com" server_url_base = None ####################################################################### # Normally I would split this into multiple files, but it simplifies # import path headaches to keep it all in one file. Sorry. # The different parts of the file are separated by banners like this one. ####################################################################### # Helpers def RelativePath(path, cwd): n = len(cwd) if path.startswith(cwd) and path[n] == '/': return path[n+1:] return path def Sub(l1, l2): return [l for l in l1 if l not in l2] def Add(l1, l2): l = l1 + Sub(l2, l1) l.sort() return l def Intersect(l1, l2): return [l for l in l1 if l in l2] ####################################################################### # RE: UNICODE STRING HANDLING # # Python distinguishes between the str (string of bytes) # and unicode (string of code points) types. Most operations # work on either one just fine, but some (like regexp matching) # require unicode, and others (like write) require str. # # As befits the language, Python hides the distinction between # unicode and str by converting between them silently, but # *only* if all the bytes/code points involved are 7-bit ASCII. # This means that if you're not careful, your program works # fine on "hello, world" and fails on "hello, 世界". And of course, # the obvious way to be careful - use static types - is unavailable. # So the only way is trial and error to find where to put explicit # conversions. # # Because more functions do implicit conversion to str (string of bytes) # than do implicit conversion to unicode (string of code points), # the convention in this module is to represent all text as str, # converting to unicode only when calling a unicode-only function # and then converting back to str as soon as possible. def typecheck(s, t): if type(s) != t: raise hg_util.Abort("type check failed: %s has type %s != %s" % (repr(s), type(s), t)) # If we have to pass unicode instead of str, ustr does that conversion clearly. def ustr(s): typecheck(s, str) return s.decode("utf-8") # Even with those, Mercurial still sometimes turns unicode into str # and then tries to use it as ascii. Change Mercurial's default. def set_mercurial_encoding_to_utf8(): from mercurial import encoding encoding.encoding = 'utf-8' set_mercurial_encoding_to_utf8() # Even with those we still run into problems. # I tried to do things by the book but could not convince # Mercurial to let me check in a change with UTF-8 in the # CL description or author field, no matter how many conversions # between str and unicode I inserted and despite changing the # default encoding. I'm tired of this game, so set the default # encoding for all of Python to 'utf-8', not 'ascii'. def default_to_utf8(): import sys stdout, __stdout__ = sys.stdout, sys.__stdout__ reload(sys) # site.py deleted setdefaultencoding; get it back sys.stdout, sys.__stdout__ = stdout, __stdout__ sys.setdefaultencoding('utf-8') default_to_utf8() ####################################################################### # Status printer for long-running commands global_status = None def set_status(s): # print >>sys.stderr, "\t", time.asctime(), s global global_status global_status = s class StatusThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): # pause a reasonable amount of time before # starting to display status messages, so that # most hg commands won't ever see them. time.sleep(30) # now show status every 15 seconds while True: time.sleep(15 - time.time() % 15) s = global_status if s is None: continue if s == "": s = "(unknown status)" print >>sys.stderr, time.asctime(), s def start_status_thread(): t = StatusThread() t.setDaemon(True) # allowed to exit if t is still running t.start() ####################################################################### # Change list parsing. # # Change lists are stored in .hg/codereview/cl.nnnnnn # where nnnnnn is the number assigned by the code review server. # Most data about a change list is stored on the code review server # too: the description, reviewer, and cc list are all stored there. # The only thing in the cl.nnnnnn file is the list of relevant files. # Also, the existence of the cl.nnnnnn file marks this repository # as the one where the change list lives. emptydiff = """Index: ~rietveld~placeholder~ =================================================================== diff --git a/~rietveld~placeholder~ b/~rietveld~placeholder~ new file mode 100644 """ class CL(object): def __init__(self, name): typecheck(name, str) self.name = name self.desc = '' self.files = [] self.reviewer = [] self.cc = [] self.url = '' self.local = False self.web = False self.copied_from = None # None means current user self.mailed = False self.private = False self.lgtm = [] def DiskText(self): cl = self s = "" if cl.copied_from: s += "Author: " + cl.copied_from + "\n\n" if cl.private: s += "Private: " + str(self.private) + "\n" s += "Mailed: " + str(self.mailed) + "\n" s += "Description:\n" s += Indent(cl.desc, "\t") s += "Files:\n" for f in cl.files: s += "\t" + f + "\n" typecheck(s, str) return s def EditorText(self): cl = self s = _change_prolog s += "\n" if cl.copied_from: s += "Author: " + cl.copied_from + "\n" if cl.url != '': s += 'URL: ' + cl.url + ' # cannot edit\n\n' if cl.private: s += "Private: True\n" s += "Reviewer: " + JoinComma(cl.reviewer) + "\n" s += "CC: " + JoinComma(cl.cc) + "\n" s += "\n" s += "Description:\n" if cl.desc == '': s += "\t\n" else: s += Indent(cl.desc, "\t") s += "\n" if cl.local or cl.name == "new": s += "Files:\n" for f in cl.files: s += "\t" + f + "\n" s += "\n" typecheck(s, str) return s def PendingText(self, quick=False): cl = self s = cl.name + ":" + "\n" s += Indent(cl.desc, "\t") s += "\n" if cl.copied_from: s += "\tAuthor: " + cl.copied_from + "\n" if not quick: s += "\tReviewer: " + JoinComma(cl.reviewer) + "\n" for (who, line) in cl.lgtm: s += "\t\t" + who + ": " + line + "\n" s += "\tCC: " + JoinComma(cl.cc) + "\n" s += "\tFiles:\n" for f in cl.files: s += "\t\t" + f + "\n" typecheck(s, str) return s def Flush(self, ui, repo): if self.name == "new": self.Upload(ui, repo, gofmt_just_warn=True, creating=True) dir = CodeReviewDir(ui, repo) path = dir + '/cl.' + self.name f = open(path+'!', "w") f.write(self.DiskText()) f.close() if sys.platform == "win32" and os.path.isfile(path): os.remove(path) os.rename(path+'!', path) if self.web and not self.copied_from: EditDesc(self.name, desc=self.desc, reviewers=JoinComma(self.reviewer), cc=JoinComma(self.cc), private=self.private) def Delete(self, ui, repo): dir = CodeReviewDir(ui, repo) os.unlink(dir + "/cl." + self.name) def Subject(self): s = line1(self.desc) if len(s) > 60: s = s[0:55] + "..." if self.name != "new": s = "code review %s: %s" % (self.name, s) typecheck(s, str) return s def Upload(self, ui, repo, send_mail=False, gofmt=True, gofmt_just_warn=False, creating=False, quiet=False): if not self.files and not creating: ui.warn("no files in change list\n") if ui.configbool("codereview", "force_gofmt", True) and gofmt: CheckFormat(ui, repo, self.files, just_warn=gofmt_just_warn) set_status("uploading CL metadata + diffs") os.chdir(repo.root) form_fields = [ ("content_upload", "1"), ("reviewers", JoinComma(self.reviewer)), ("cc", JoinComma(self.cc)), ("description", self.desc), ("base_hashes", ""), ] if self.name != "new": form_fields.append(("issue", self.name)) vcs = None # We do not include files when creating the issue, # because we want the patch sets to record the repository # and base revision they are diffs against. We use the patch # set message for that purpose, but there is no message with # the first patch set. Instead the message gets used as the # new CL's overall subject. So omit the diffs when creating # and then we'll run an immediate upload. # This has the effect that every CL begins with an empty "Patch set 1". if self.files and not creating: vcs = MercurialVCS(upload_options, ui, repo) data = vcs.GenerateDiff(self.files) files = vcs.GetBaseFiles(data) if len(data) > MAX_UPLOAD_SIZE: uploaded_diff_file = [] form_fields.append(("separate_patches", "1")) else: uploaded_diff_file = [("data", "data.diff", data)] else: uploaded_diff_file = [("data", "data.diff", emptydiff)] if vcs and self.name != "new": form_fields.append(("subject", "diff -r " + vcs.base_rev + " " + ui.expandpath("default"))) else: # First upload sets the subject for the CL itself. form_fields.append(("subject", self.Subject())) ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file) response_body = MySend("/upload", body, content_type=ctype) patchset = None msg = response_body lines = msg.splitlines() if len(lines) >= 2: msg = lines[0] patchset = lines[1].strip() patches = [x.split(" ", 1) for x in lines[2:]] if response_body.startswith("Issue updated.") and quiet: pass else: ui.status(msg + "\n") set_status("uploaded CL metadata + diffs") if not response_body.startswith("Issue created.") and not response_body.startswith("Issue updated."): raise hg_util.Abort("failed to update issue: " + response_body) issue = msg[msg.rfind("/")+1:] self.name = issue if not self.url: self.url = server_url_base + self.name if not uploaded_diff_file: set_status("uploading patches") patches = UploadSeparatePatches(issue, rpc, patchset, data, upload_options) if vcs: set_status("uploading base files") vcs.UploadBaseFiles(issue, rpc, patches, patchset, upload_options, files) if send_mail: set_status("sending mail") MySend("/" + issue + "/mail", payload="") self.web = True set_status("flushing changes to disk") self.Flush(ui, repo) return def Mail(self, ui, repo): pmsg = "Hello " + JoinComma(self.reviewer) if self.cc: pmsg += " (cc: %s)" % (', '.join(self.cc),) pmsg += ",\n" pmsg += "\n" repourl = ui.expandpath("default") if not self.mailed: pmsg += "I'd like you to review this change to\n" + repourl + "\n" else: pmsg += "Please take another look.\n" typecheck(pmsg, str) PostMessage(ui, self.name, pmsg, subject=self.Subject()) self.mailed = True self.Flush(ui, repo) def GoodCLName(name): typecheck(name, str) return re.match("^[0-9]+$", name) def ParseCL(text, name): typecheck(text, str) typecheck(name, str) sname = None lineno = 0 sections = { 'Author': '', 'Description': '', 'Files': '', 'URL': '', 'Reviewer': '', 'CC': '', 'Mailed': '', 'Private': '', } for line in text.split('\n'): lineno += 1 line = line.rstrip() if line != '' and line[0] == '#': continue if line == '' or line[0] == ' ' or line[0] == '\t': if sname == None and line != '': return None, lineno, 'text outside section' if sname != None: sections[sname] += line + '\n' continue p = line.find(':') if p >= 0: s, val = line[:p].strip(), line[p+1:].strip() if s in sections: sname = s if val != '': sections[sname] += val + '\n' continue return None, lineno, 'malformed section header' for k in sections: sections[k] = StripCommon(sections[k]).rstrip() cl = CL(name) if sections['Author']: cl.copied_from = sections['Author'] cl.desc = sections['Description'] for line in sections['Files'].split('\n'): i = line.find('#') if i >= 0: line = line[0:i].rstrip() line = line.strip() if line == '': continue cl.files.append(line) cl.reviewer = SplitCommaSpace(sections['Reviewer']) cl.cc = SplitCommaSpace(sections['CC']) cl.url = sections['URL'] if sections['Mailed'] != 'False': # Odd default, but avoids spurious mailings when # reading old CLs that do not have a Mailed: line. # CLs created with this update will always have # Mailed: False on disk. cl.mailed = True if sections['Private'] in ('True', 'true', 'Yes', 'yes'): cl.private = True if cl.desc == '': cl.desc = '' return cl, 0, '' def SplitCommaSpace(s): typecheck(s, str) s = s.strip() if s == "": return [] return re.split(", *", s) def CutDomain(s): typecheck(s, str) i = s.find('@') if i >= 0: s = s[0:i] return s def JoinComma(l): for s in l: typecheck(s, str) return ", ".join(l) def ExceptionDetail(): s = str(sys.exc_info()[0]) if s.startswith(""): s = s[7:-2] elif s.startswith(""): s = s[8:-2] arg = str(sys.exc_info()[1]) if len(arg) > 0: s += ": " + arg return s def IsLocalCL(ui, repo, name): return GoodCLName(name) and os.access(CodeReviewDir(ui, repo) + "/cl." + name, 0) # Load CL from disk and/or the web. def LoadCL(ui, repo, name, web=True): typecheck(name, str) set_status("loading CL " + name) if not GoodCLName(name): return None, "invalid CL name" dir = CodeReviewDir(ui, repo) path = dir + "cl." + name if os.access(path, 0): ff = open(path) text = ff.read() ff.close() cl, lineno, err = ParseCL(text, name) if err != "": return None, "malformed CL data: "+err cl.local = True else: cl = CL(name) if web: set_status("getting issue metadata from web") d = JSONGet(ui, "/api/" + name + "?messages=true") set_status(None) if d is None: return None, "cannot load CL %s from server" % (name,) if 'owner_email' not in d or 'issue' not in d or str(d['issue']) != name: return None, "malformed response loading CL data from code review server" cl.dict = d cl.reviewer = d.get('reviewers', []) cl.cc = d.get('cc', []) if cl.local and cl.copied_from and cl.desc: # local copy of CL written by someone else # and we saved a description. use that one, # so that committers can edit the description # before doing hg submit. pass else: cl.desc = d.get('description', "") cl.url = server_url_base + name cl.web = True cl.private = d.get('private', False) != False cl.lgtm = [] for m in d.get('messages', []): if m.get('approval', False) == True: who = re.sub('@.*', '', m.get('sender', '')) text = re.sub("\n(.|\n)*", '', m.get('text', '')) cl.lgtm.append((who, text)) set_status("loaded CL " + name) return cl, '' class LoadCLThread(threading.Thread): def __init__(self, ui, repo, dir, f, web): threading.Thread.__init__(self) self.ui = ui self.repo = repo self.dir = dir self.f = f self.web = web self.cl = None def run(self): cl, err = LoadCL(self.ui, self.repo, self.f[3:], web=self.web) if err != '': self.ui.warn("loading "+self.dir+self.f+": " + err + "\n") return self.cl = cl # Load all the CLs from this repository. def LoadAllCL(ui, repo, web=True): dir = CodeReviewDir(ui, repo) m = {} files = [f for f in os.listdir(dir) if f.startswith('cl.')] if not files: return m active = [] first = True for f in files: t = LoadCLThread(ui, repo, dir, f, web) t.start() if web and first: # first request: wait in case it needs to authenticate # otherwise we get lots of user/password prompts # running in parallel. t.join() if t.cl: m[t.cl.name] = t.cl first = False else: active.append(t) for t in active: t.join() if t.cl: m[t.cl.name] = t.cl return m # Find repository root. On error, ui.warn and return None def RepoDir(ui, repo): url = repo.url(); if not url.startswith('file:'): ui.warn("repository %s is not in local file system\n" % (url,)) return None url = url[5:] if url.endswith('/'): url = url[:-1] typecheck(url, str) return url # Find (or make) code review directory. On error, ui.warn and return None def CodeReviewDir(ui, repo): dir = RepoDir(ui, repo) if dir == None: return None dir += '/.hg/codereview/' if not os.path.isdir(dir): try: os.mkdir(dir, 0700) except: ui.warn('cannot mkdir %s: %s\n' % (dir, ExceptionDetail())) return None typecheck(dir, str) return dir # Turn leading tabs into spaces, so that the common white space # prefix doesn't get confused when people's editors write out # some lines with spaces, some with tabs. Only a heuristic # (some editors don't use 8 spaces either) but a useful one. def TabsToSpaces(line): i = 0 while i < len(line) and line[i] == '\t': i += 1 return ' '*(8*i) + line[i:] # Strip maximal common leading white space prefix from text def StripCommon(text): typecheck(text, str) ws = None for line in text.split('\n'): line = line.rstrip() if line == '': continue line = TabsToSpaces(line) white = line[:len(line)-len(line.lstrip())] if ws == None: ws = white else: common = '' for i in range(min(len(white), len(ws))+1): if white[0:i] == ws[0:i]: common = white[0:i] ws = common if ws == '': break if ws == None: return text t = '' for line in text.split('\n'): line = line.rstrip() line = TabsToSpaces(line) if line.startswith(ws): line = line[len(ws):] if line == '' and t == '': continue t += line + '\n' while len(t) >= 2 and t[-2:] == '\n\n': t = t[:-1] typecheck(t, str) return t # Indent text with indent. def Indent(text, indent): typecheck(text, str) typecheck(indent, str) t = '' for line in text.split('\n'): t += indent + line + '\n' typecheck(t, str) return t # Return the first line of l def line1(text): typecheck(text, str) return text.split('\n')[0] _change_prolog = """# Change list. # Lines beginning with # are ignored. # Multi-line values should be indented. """ desc_re = '^(.+: |(tag )?(release|weekly)\.|fix build|undo CL)' desc_msg = '''Your CL description appears not to use the standard form. The first line of your change description is conventionally a one-line summary of the change, prefixed by the primary affected package, and is used as the subject for code review mail; the rest of the description elaborates. Examples: encoding/rot13: new package math: add IsInf, IsNaN net: fix cname in LookupHost unicode: update to Unicode 5.0.2 ''' def promptyesno(ui, msg): return ui.promptchoice(msg, ["&yes", "&no"], 0) == 0 def promptremove(ui, repo, f): if promptyesno(ui, "hg remove %s (y/n)?" % (f,)): if hg_commands.remove(ui, repo, 'path:'+f) != 0: ui.warn("error removing %s" % (f,)) def promptadd(ui, repo, f): if promptyesno(ui, "hg add %s (y/n)?" % (f,)): if hg_commands.add(ui, repo, 'path:'+f) != 0: ui.warn("error adding %s" % (f,)) def EditCL(ui, repo, cl): set_status(None) # do not show status s = cl.EditorText() while True: s = ui.edit(s, ui.username()) # We can't trust Mercurial + Python not to die before making the change, # so, by popular demand, just scribble the most recent CL edit into # $(hg root)/last-change so that if Mercurial does die, people # can look there for their work. try: f = open(repo.root+"/last-change", "w") f.write(s) f.close() except: pass clx, line, err = ParseCL(s, cl.name) if err != '': if not promptyesno(ui, "error parsing change list: line %d: %s\nre-edit (y/n)?" % (line, err)): return "change list not modified" continue # Check description. if clx.desc == '': if promptyesno(ui, "change list should have a description\nre-edit (y/n)?"): continue elif re.search('', clx.desc): if promptyesno(ui, "change list description omits reason for undo\nre-edit (y/n)?"): continue elif not re.match(desc_re, clx.desc.split('\n')[0]): if promptyesno(ui, desc_msg + "re-edit (y/n)?"): continue # Check file list for files that need to be hg added or hg removed # or simply aren't understood. pats = ['path:'+f for f in clx.files] changed = hg_matchPattern(ui, repo, *pats, modified=True, added=True, removed=True) deleted = hg_matchPattern(ui, repo, *pats, deleted=True) unknown = hg_matchPattern(ui, repo, *pats, unknown=True) ignored = hg_matchPattern(ui, repo, *pats, ignored=True) clean = hg_matchPattern(ui, repo, *pats, clean=True) files = [] for f in clx.files: if f in changed: files.append(f) continue if f in deleted: promptremove(ui, repo, f) files.append(f) continue if f in unknown: promptadd(ui, repo, f) files.append(f) continue if f in ignored: ui.warn("error: %s is excluded by .hgignore; omitting\n" % (f,)) continue if f in clean: ui.warn("warning: %s is listed in the CL but unchanged\n" % (f,)) files.append(f) continue p = repo.root + '/' + f if os.path.isfile(p): ui.warn("warning: %s is a file but not known to hg\n" % (f,)) files.append(f) continue if os.path.isdir(p): ui.warn("error: %s is a directory, not a file; omitting\n" % (f,)) continue ui.warn("error: %s does not exist; omitting\n" % (f,)) clx.files = files cl.desc = clx.desc cl.reviewer = clx.reviewer cl.cc = clx.cc cl.files = clx.files cl.private = clx.private break return "" # For use by submit, etc. (NOT by change) # Get change list number or list of files from command line. # If files are given, make a new change list. def CommandLineCL(ui, repo, pats, opts, defaultcc=None): if len(pats) > 0 and GoodCLName(pats[0]): if len(pats) != 1: return None, "cannot specify change number and file names" if opts.get('message'): return None, "cannot use -m with existing CL" cl, err = LoadCL(ui, repo, pats[0], web=True) if err != "": return None, err else: cl = CL("new") cl.local = True cl.files = ChangedFiles(ui, repo, pats, taken=Taken(ui, repo)) if not cl.files: return None, "no files changed" if opts.get('reviewer'): cl.reviewer = Add(cl.reviewer, SplitCommaSpace(opts.get('reviewer'))) if opts.get('cc'): cl.cc = Add(cl.cc, SplitCommaSpace(opts.get('cc'))) if defaultcc: cl.cc = Add(cl.cc, defaultcc) if cl.name == "new": if opts.get('message'): cl.desc = opts.get('message') else: err = EditCL(ui, repo, cl) if err != '': return None, err return cl, "" ####################################################################### # Change list file management # Return list of changed files in repository that match pats. # The patterns came from the command line, so we warn # if they have no effect or cannot be understood. def ChangedFiles(ui, repo, pats, taken=None): taken = taken or {} # Run each pattern separately so that we can warn about # patterns that didn't do anything useful. for p in pats: for f in hg_matchPattern(ui, repo, p, unknown=True): promptadd(ui, repo, f) for f in hg_matchPattern(ui, repo, p, removed=True): promptremove(ui, repo, f) files = hg_matchPattern(ui, repo, p, modified=True, added=True, removed=True) for f in files: if f in taken: ui.warn("warning: %s already in CL %s\n" % (f, taken[f].name)) if not files: ui.warn("warning: %s did not match any modified files\n" % (p,)) # Again, all at once (eliminates duplicates) l = hg_matchPattern(ui, repo, *pats, modified=True, added=True, removed=True) l.sort() if taken: l = Sub(l, taken.keys()) return l # Return list of changed files in repository that match pats and still exist. def ChangedExistingFiles(ui, repo, pats, opts): l = hg_matchPattern(ui, repo, *pats, modified=True, added=True) l.sort() return l # Return list of files claimed by existing CLs def Taken(ui, repo): all = LoadAllCL(ui, repo, web=False) taken = {} for _, cl in all.items(): for f in cl.files: taken[f] = cl return taken # Return list of changed files that are not claimed by other CLs def DefaultFiles(ui, repo, pats): return ChangedFiles(ui, repo, pats, taken=Taken(ui, repo)) ####################################################################### # File format checking. def CheckFormat(ui, repo, files, just_warn=False): set_status("running gofmt") CheckGofmt(ui, repo, files, just_warn) CheckTabfmt(ui, repo, files, just_warn) # Check that gofmt run on the list of files does not change them def CheckGofmt(ui, repo, files, just_warn): files = gofmt_required(files) if not files: return cwd = os.getcwd() files = [RelativePath(repo.root + '/' + f, cwd) for f in files] files = [f for f in files if os.access(f, 0)] if not files: return try: cmd = subprocess.Popen(["gofmt", "-l"] + files, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=sys.platform != "win32") cmd.stdin.close() except: raise hg_util.Abort("gofmt: " + ExceptionDetail()) data = cmd.stdout.read() errors = cmd.stderr.read() cmd.wait() set_status("done with gofmt") if len(errors) > 0: ui.warn("gofmt errors:\n" + errors.rstrip() + "\n") return if len(data) > 0: msg = "gofmt needs to format these files (run hg gofmt):\n" + Indent(data, "\t").rstrip() if just_warn: ui.warn("warning: " + msg + "\n") else: raise hg_util.Abort(msg) return # Check that *.[chys] files indent using tabs. def CheckTabfmt(ui, repo, files, just_warn): files = [f for f in files if f.startswith('src/') and re.search(r"\.[chys]$", f) and not re.search(r"\.tab\.[ch]$", f)] if not files: return cwd = os.getcwd() files = [RelativePath(repo.root + '/' + f, cwd) for f in files] files = [f for f in files if os.access(f, 0)] badfiles = [] for f in files: try: for line in open(f, 'r'): # Four leading spaces is enough to complain about, # except that some Plan 9 code uses four spaces as the label indent, # so allow that. if line.startswith(' ') and not re.match(' [A-Za-z0-9_]+:', line): badfiles.append(f) break except: # ignore cannot open file, etc. pass if len(badfiles) > 0: msg = "these files use spaces for indentation (use tabs instead):\n\t" + "\n\t".join(badfiles) if just_warn: ui.warn("warning: " + msg + "\n") else: raise hg_util.Abort(msg) return ####################################################################### # CONTRIBUTORS file parsing contributorsCache = None contributorsURL = None def ReadContributors(ui, repo): global contributorsCache if contributorsCache is not None: return contributorsCache try: if contributorsURL is not None: opening = contributorsURL f = urllib2.urlopen(contributorsURL) else: opening = repo.root + '/CONTRIBUTORS' f = open(repo.root + '/CONTRIBUTORS', 'r') except: ui.write("warning: cannot open %s: %s\n" % (opening, ExceptionDetail())) return contributors = {} for line in f: # CONTRIBUTORS is a list of lines like: # Person # Person # The first email address is the one used in commit logs. if line.startswith('#'): continue m = re.match(r"([^<>]+\S)\s+(<[^<>\s]+>)((\s+<[^<>\s]+>)*)\s*$", line) if m: name = m.group(1) email = m.group(2)[1:-1] contributors[email.lower()] = (name, email) for extra in m.group(3).split(): contributors[extra[1:-1].lower()] = (name, email) contributorsCache = contributors return contributors def CheckContributor(ui, repo, user=None): set_status("checking CONTRIBUTORS file") user, userline = FindContributor(ui, repo, user, warn=False) if not userline: raise hg_util.Abort("cannot find %s in CONTRIBUTORS" % (user,)) return userline def FindContributor(ui, repo, user=None, warn=True): if not user: user = ui.config("ui", "username") if not user: raise hg_util.Abort("[ui] username is not configured in .hgrc") user = user.lower() m = re.match(r".*<(.*)>", user) if m: user = m.group(1) contributors = ReadContributors(ui, repo) if user not in contributors: if warn: ui.warn("warning: cannot find %s in CONTRIBUTORS\n" % (user,)) return user, None user, email = contributors[user] return email, "%s <%s>" % (user, email) ####################################################################### # Mercurial helper functions. # Read http://mercurial.selenic.com/wiki/MercurialApi before writing any of these. # We use the ui.pushbuffer/ui.popbuffer + hg_commands.xxx tricks for all interaction # with Mercurial. It has proved the most stable as they make changes. hgversion = hg_util.version() # We require Mercurial 1.9 and suggest Mercurial 2.0. # The details of the scmutil package changed then, # so allowing earlier versions would require extra band-aids below. # Ubuntu 11.10 ships with Mercurial 1.9.1 as the default version. hg_required = "1.9" hg_suggested = "2.0" old_message = """ The code review extension requires Mercurial """+hg_required+""" or newer. You are using Mercurial """+hgversion+""". To install a new Mercurial, use sudo easy_install mercurial=="""+hg_suggested+""" or visit http://mercurial.selenic.com/downloads/. """ linux_message = """ You may need to clear your current Mercurial installation by running: sudo apt-get remove mercurial mercurial-common sudo rm -rf /etc/mercurial """ if hgversion < hg_required: msg = old_message if os.access("/etc/mercurial", 0): msg += linux_message raise hg_util.Abort(msg) from mercurial.hg import clean as hg_clean from mercurial import cmdutil as hg_cmdutil from mercurial import error as hg_error from mercurial import match as hg_match from mercurial import node as hg_node class uiwrap(object): def __init__(self, ui): self.ui = ui ui.pushbuffer() self.oldQuiet = ui.quiet ui.quiet = True self.oldVerbose = ui.verbose ui.verbose = False def output(self): ui = self.ui ui.quiet = self.oldQuiet ui.verbose = self.oldVerbose return ui.popbuffer() def to_slash(path): if sys.platform == "win32": return path.replace('\\', '/') return path def hg_matchPattern(ui, repo, *pats, **opts): w = uiwrap(ui) hg_commands.status(ui, repo, *pats, **opts) text = w.output() ret = [] prefix = to_slash(os.path.realpath(repo.root))+'/' for line in text.split('\n'): f = line.split() if len(f) > 1: if len(pats) > 0: # Given patterns, Mercurial shows relative to cwd p = to_slash(os.path.realpath(f[1])) if not p.startswith(prefix): print >>sys.stderr, "File %s not in repo root %s.\n" % (p, prefix) else: ret.append(p[len(prefix):]) else: # Without patterns, Mercurial shows relative to root (what we want) ret.append(to_slash(f[1])) return ret def hg_heads(ui, repo): w = uiwrap(ui) hg_commands.heads(ui, repo) return w.output() noise = [ "", "resolving manifests", "searching for changes", "couldn't find merge tool hgmerge", "adding changesets", "adding manifests", "adding file changes", "all local heads known remotely", ] def isNoise(line): line = str(line) for x in noise: if line == x: return True return False def hg_incoming(ui, repo): w = uiwrap(ui) ret = hg_commands.incoming(ui, repo, force=False, bundle="") if ret and ret != 1: raise hg_util.Abort(ret) return w.output() def hg_log(ui, repo, **opts): for k in ['date', 'keyword', 'rev', 'user']: if not opts.has_key(k): opts[k] = "" w = uiwrap(ui) ret = hg_commands.log(ui, repo, **opts) if ret: raise hg_util.Abort(ret) return w.output() def hg_outgoing(ui, repo, **opts): w = uiwrap(ui) ret = hg_commands.outgoing(ui, repo, **opts) if ret and ret != 1: raise hg_util.Abort(ret) return w.output() def hg_pull(ui, repo, **opts): w = uiwrap(ui) ui.quiet = False ui.verbose = True # for file list err = hg_commands.pull(ui, repo, **opts) for line in w.output().split('\n'): if isNoise(line): continue if line.startswith('moving '): line = 'mv ' + line[len('moving '):] if line.startswith('getting ') and line.find(' to ') >= 0: line = 'mv ' + line[len('getting '):] if line.startswith('getting '): line = '+ ' + line[len('getting '):] if line.startswith('removing '): line = '- ' + line[len('removing '):] ui.write(line + '\n') return err def hg_push(ui, repo, **opts): w = uiwrap(ui) ui.quiet = False ui.verbose = True err = hg_commands.push(ui, repo, **opts) for line in w.output().split('\n'): if not isNoise(line): ui.write(line + '\n') return err def hg_commit(ui, repo, *pats, **opts): return hg_commands.commit(ui, repo, *pats, **opts) ####################################################################### # Mercurial precommit hook to disable commit except through this interface. commit_okay = False def precommithook(ui, repo, **opts): if commit_okay: return False # False means okay. ui.write("\ncodereview extension enabled; use mail, upload, or submit instead of commit\n\n") return True ####################################################################### # @clnumber file pattern support # We replace scmutil.match with the MatchAt wrapper to add the @clnumber pattern. match_repo = None match_ui = None match_orig = None def InstallMatch(ui, repo): global match_repo global match_ui global match_orig match_ui = ui match_repo = repo from mercurial import scmutil match_orig = scmutil.match scmutil.match = MatchAt def MatchAt(ctx, pats=None, opts=None, globbed=False, default='relpath'): taken = [] files = [] pats = pats or [] opts = opts or {} for p in pats: if p.startswith('@'): taken.append(p) clname = p[1:] if clname == "default": files = DefaultFiles(match_ui, match_repo, []) else: if not GoodCLName(clname): raise hg_util.Abort("invalid CL name " + clname) cl, err = LoadCL(match_repo.ui, match_repo, clname, web=False) if err != '': raise hg_util.Abort("loading CL " + clname + ": " + err) if not cl.files: raise hg_util.Abort("no files in CL " + clname) files = Add(files, cl.files) pats = Sub(pats, taken) + ['path:'+f for f in files] # work-around for http://selenic.com/hg/rev/785bbc8634f8 if not hasattr(ctx, 'match'): ctx = ctx[None] return match_orig(ctx, pats=pats, opts=opts, globbed=globbed, default=default) ####################################################################### # Commands added by code review extension. # As of Mercurial 2.1 the commands are all required to return integer # exit codes, whereas earlier versions allowed returning arbitrary strings # to be printed as errors. We wrap the old functions to make sure we # always return integer exit codes now. Otherwise Mercurial dies # with a TypeError traceback (unsupported operand type(s) for &: 'str' and 'int'). # Introduce a Python decorator to convert old functions to the new # stricter convention. def hgcommand(f): def wrapped(ui, repo, *pats, **opts): err = f(ui, repo, *pats, **opts) if type(err) is int: return err if not err: return 0 raise hg_util.Abort(err) wrapped.__doc__ = f.__doc__ return wrapped ####################################################################### # hg change @hgcommand def change(ui, repo, *pats, **opts): """create, edit or delete a change list Create, edit or delete a change list. A change list is a group of files to be reviewed and submitted together, plus a textual description of the change. Change lists are referred to by simple alphanumeric names. Changes must be reviewed before they can be submitted. In the absence of options, the change command opens the change list for editing in the default editor. Deleting a change with the -d or -D flag does not affect the contents of the files listed in that change. To revert the files listed in a change, use hg revert @123456 before running hg change -d 123456. """ if codereview_disabled: return codereview_disabled dirty = {} if len(pats) > 0 and GoodCLName(pats[0]): name = pats[0] if len(pats) != 1: return "cannot specify CL name and file patterns" pats = pats[1:] cl, err = LoadCL(ui, repo, name, web=True) if err != '': return err if not cl.local and (opts["stdin"] or not opts["stdout"]): return "cannot change non-local CL " + name else: name = "new" cl = CL("new") if repo[None].branch() != "default": return "cannot create CL outside default branch; switch with 'hg update default'" dirty[cl] = True files = ChangedFiles(ui, repo, pats, taken=Taken(ui, repo)) if opts["delete"] or opts["deletelocal"]: if opts["delete"] and opts["deletelocal"]: return "cannot use -d and -D together" flag = "-d" if opts["deletelocal"]: flag = "-D" if name == "new": return "cannot use "+flag+" with file patterns" if opts["stdin"] or opts["stdout"]: return "cannot use "+flag+" with -i or -o" if not cl.local: return "cannot change non-local CL " + name if opts["delete"]: if cl.copied_from: return "original author must delete CL; hg change -D will remove locally" PostMessage(ui, cl.name, "*** Abandoned ***", send_mail=cl.mailed) EditDesc(cl.name, closed=True, private=cl.private) cl.Delete(ui, repo) return if opts["stdin"]: s = sys.stdin.read() clx, line, err = ParseCL(s, name) if err != '': return "error parsing change list: line %d: %s" % (line, err) if clx.desc is not None: cl.desc = clx.desc; dirty[cl] = True if clx.reviewer is not None: cl.reviewer = clx.reviewer dirty[cl] = True if clx.cc is not None: cl.cc = clx.cc dirty[cl] = True if clx.files is not None: cl.files = clx.files dirty[cl] = True if clx.private != cl.private: cl.private = clx.private dirty[cl] = True if not opts["stdin"] and not opts["stdout"]: if name == "new": cl.files = files err = EditCL(ui, repo, cl) if err != "": return err dirty[cl] = True for d, _ in dirty.items(): name = d.name d.Flush(ui, repo) if name == "new": d.Upload(ui, repo, quiet=True) if opts["stdout"]: ui.write(cl.EditorText()) elif opts["pending"]: ui.write(cl.PendingText()) elif name == "new": if ui.quiet: ui.write(cl.name) else: ui.write("CL created: " + cl.url + "\n") return ####################################################################### # hg code-login (broken?) @hgcommand def code_login(ui, repo, **opts): """log in to code review server Logs in to the code review server, saving a cookie in a file in your home directory. """ if codereview_disabled: return codereview_disabled MySend(None) ####################################################################### # hg clpatch / undo / release-apply / download # All concerned with applying or unapplying patches to the repository. @hgcommand def clpatch(ui, repo, clname, **opts): """import a patch from the code review server Imports a patch from the code review server into the local client. If the local client has already modified any of the files that the patch modifies, this command will refuse to apply the patch. Submitting an imported patch will keep the original author's name as the Author: line but add your own name to a Committer: line. """ if repo[None].branch() != "default": return "cannot run hg clpatch outside default branch" return clpatch_or_undo(ui, repo, clname, opts, mode="clpatch") @hgcommand def undo(ui, repo, clname, **opts): """undo the effect of a CL Creates a new CL that undoes an earlier CL. After creating the CL, opens the CL text for editing so that you can add the reason for the undo to the description. """ if repo[None].branch() != "default": return "cannot run hg undo outside default branch" return clpatch_or_undo(ui, repo, clname, opts, mode="undo") @hgcommand def release_apply(ui, repo, clname, **opts): """apply a CL to the release branch Creates a new CL copying a previously committed change from the main branch to the release branch. The current client must either be clean or already be in the release branch. The release branch must be created by starting with a clean client, disabling the code review plugin, and running: hg update weekly.YYYY-MM-DD hg branch release-branch.rNN hg commit -m 'create release-branch.rNN' hg push --new-branch Then re-enable the code review plugin. People can test the release branch by running hg update release-branch.rNN in a clean client. To return to the normal tree, hg update default Move changes since the weekly into the release branch using hg release-apply followed by the usual code review process and hg submit. When it comes time to tag the release, record the final long-form tag of the release-branch.rNN in the *default* branch's .hgtags file. That is, run hg update default and then edit .hgtags as you would for a weekly. """ c = repo[None] if not releaseBranch: return "no active release branches" if c.branch() != releaseBranch: if c.modified() or c.added() or c.removed(): raise hg_util.Abort("uncommitted local changes - cannot switch branches") err = hg_clean(repo, releaseBranch) if err: return err try: err = clpatch_or_undo(ui, repo, clname, opts, mode="backport") if err: raise hg_util.Abort(err) except Exception, e: hg_clean(repo, "default") raise e return None def rev2clname(rev): # Extract CL name from revision description. # The last line in the description that is a codereview URL is the real one. # Earlier lines might be part of the user-written description. all = re.findall('(?m)^http://codereview.appspot.com/([0-9]+)$', rev.description()) if len(all) > 0: return all[-1] return "" undoHeader = """undo CL %s / %s ««« original CL description """ undoFooter = """ »»» """ backportHeader = """[%s] %s ««« CL %s / %s """ backportFooter = """ »»» """ # Implementation of clpatch/undo. def clpatch_or_undo(ui, repo, clname, opts, mode): if codereview_disabled: return codereview_disabled if mode == "undo" or mode == "backport": # Find revision in Mercurial repository. # Assume CL number is 7+ decimal digits. # Otherwise is either change log sequence number (fewer decimal digits), # hexadecimal hash, or tag name. # Mercurial will fall over long before the change log # sequence numbers get to be 7 digits long. if re.match('^[0-9]{7,}$', clname): found = False for r in hg_log(ui, repo, keyword="codereview.appspot.com/"+clname, limit=100, template="{node}\n").split(): rev = repo[r] # Last line with a code review URL is the actual review URL. # Earlier ones might be part of the CL description. n = rev2clname(rev) if n == clname: found = True break if not found: return "cannot find CL %s in local repository" % clname else: rev = repo[clname] if not rev: return "unknown revision %s" % clname clname = rev2clname(rev) if clname == "": return "cannot find CL name in revision description" # Create fresh CL and start with patch that would reverse the change. vers = hg_node.short(rev.node()) cl = CL("new") desc = str(rev.description()) if mode == "undo": cl.desc = (undoHeader % (clname, vers)) + desc + undoFooter else: cl.desc = (backportHeader % (releaseBranch, line1(desc), clname, vers)) + desc + undoFooter v1 = vers v0 = hg_node.short(rev.parents()[0].node()) if mode == "undo": arg = v1 + ":" + v0 else: vers = v0 arg = v0 + ":" + v1 patch = RunShell(["hg", "diff", "--git", "-r", arg]) else: # clpatch cl, vers, patch, err = DownloadCL(ui, repo, clname) if err != "": return err if patch == emptydiff: return "codereview issue %s has no diff" % clname # find current hg version (hg identify) ctx = repo[None] parents = ctx.parents() id = '+'.join([hg_node.short(p.node()) for p in parents]) # if version does not match the patch version, # try to update the patch line numbers. if vers != "" and id != vers: # "vers in repo" gives the wrong answer # on some versions of Mercurial. Instead, do the actual # lookup and catch the exception. try: repo[vers].description() except: return "local repository is out of date; sync to get %s" % (vers) patch1, err = portPatch(repo, patch, vers, id) if err != "": if not opts["ignore_hgpatch_failure"]: return "codereview issue %s is out of date: %s (%s->%s)" % (clname, err, vers, id) else: patch = patch1 argv = ["hgpatch"] if opts["no_incoming"] or mode == "backport": argv += ["--checksync=false"] try: cmd = subprocess.Popen(argv, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, close_fds=sys.platform != "win32") except: return "hgpatch: " + ExceptionDetail() + "\nInstall hgpatch with:\n$ go get code.google.com/p/go.codereview/cmd/hgpatch\n" out, err = cmd.communicate(patch) if cmd.returncode != 0 and not opts["ignore_hgpatch_failure"]: return "hgpatch failed" cl.local = True cl.files = out.strip().split() if not cl.files and not opts["ignore_hgpatch_failure"]: return "codereview issue %s has no changed files" % clname files = ChangedFiles(ui, repo, []) extra = Sub(cl.files, files) if extra: ui.warn("warning: these files were listed in the patch but not changed:\n\t" + "\n\t".join(extra) + "\n") cl.Flush(ui, repo) if mode == "undo": err = EditCL(ui, repo, cl) if err != "": return "CL created, but error editing: " + err cl.Flush(ui, repo) else: ui.write(cl.PendingText() + "\n") # portPatch rewrites patch from being a patch against # oldver to being a patch against newver. def portPatch(repo, patch, oldver, newver): lines = patch.splitlines(True) # True = keep \n delta = None for i in range(len(lines)): line = lines[i] if line.startswith('--- a/'): file = line[6:-1] delta = fileDeltas(repo, file, oldver, newver) if not delta or not line.startswith('@@ '): continue # @@ -x,y +z,w @@ means the patch chunk replaces # the original file's line numbers x up to x+y with the # line numbers z up to z+w in the new file. # Find the delta from x in the original to the same # line in the current version and add that delta to both # x and z. m = re.match('@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@', line) if not m: return None, "error parsing patch line numbers" n1, len1, n2, len2 = int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)) d, err = lineDelta(delta, n1, len1) if err != "": return "", err n1 += d n2 += d lines[i] = "@@ -%d,%d +%d,%d @@\n" % (n1, len1, n2, len2) newpatch = ''.join(lines) return newpatch, "" # fileDelta returns the line number deltas for the given file's # changes from oldver to newver. # The deltas are a list of (n, len, newdelta) triples that say # lines [n, n+len) were modified, and after that range the # line numbers are +newdelta from what they were before. def fileDeltas(repo, file, oldver, newver): cmd = ["hg", "diff", "--git", "-r", oldver + ":" + newver, "path:" + file] data = RunShell(cmd, silent_ok=True) deltas = [] for line in data.splitlines(): m = re.match('@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@', line) if not m: continue n1, len1, n2, len2 = int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)) deltas.append((n1, len1, n2+len2-(n1+len1))) return deltas # lineDelta finds the appropriate line number delta to apply to the lines [n, n+len). # It returns an error if those lines were rewritten by the patch. def lineDelta(deltas, n, len): d = 0 for (old, oldlen, newdelta) in deltas: if old >= n+len: break if old+len > n: return 0, "patch and recent changes conflict" d = newdelta return d, "" @hgcommand def download(ui, repo, clname, **opts): """download a change from the code review server Download prints a description of the given change list followed by its diff, downloaded from the code review server. """ if codereview_disabled: return codereview_disabled cl, vers, patch, err = DownloadCL(ui, repo, clname) if err != "": return err ui.write(cl.EditorText() + "\n") ui.write(patch + "\n") return ####################################################################### # hg file @hgcommand def file(ui, repo, clname, pat, *pats, **opts): """assign files to or remove files from a change list Assign files to or (with -d) remove files from a change list. The -d option only removes files from the change list. It does not edit them or remove them from the repository. """ if codereview_disabled: return codereview_disabled pats = tuple([pat] + list(pats)) if not GoodCLName(clname): return "invalid CL name " + clname dirty = {} cl, err = LoadCL(ui, repo, clname, web=False) if err != '': return err if not cl.local: return "cannot change non-local CL " + clname files = ChangedFiles(ui, repo, pats) if opts["delete"]: oldfiles = Intersect(files, cl.files) if oldfiles: if not ui.quiet: ui.status("# Removing files from CL. To undo:\n") ui.status("# cd %s\n" % (repo.root)) for f in oldfiles: ui.status("# hg file %s %s\n" % (cl.name, f)) cl.files = Sub(cl.files, oldfiles) cl.Flush(ui, repo) else: ui.status("no such files in CL") return if not files: return "no such modified files" files = Sub(files, cl.files) taken = Taken(ui, repo) warned = False for f in files: if f in taken: if not warned and not ui.quiet: ui.status("# Taking files from other CLs. To undo:\n") ui.status("# cd %s\n" % (repo.root)) warned = True ocl = taken[f] if not ui.quiet: ui.status("# hg file %s %s\n" % (ocl.name, f)) if ocl not in dirty: ocl.files = Sub(ocl.files, files) dirty[ocl] = True cl.files = Add(cl.files, files) dirty[cl] = True for d, _ in dirty.items(): d.Flush(ui, repo) return ####################################################################### # hg gofmt @hgcommand def gofmt(ui, repo, *pats, **opts): """apply gofmt to modified files Applies gofmt to the modified files in the repository that match the given patterns. """ if codereview_disabled: return codereview_disabled files = ChangedExistingFiles(ui, repo, pats, opts) files = gofmt_required(files) if not files: return "no modified go files" cwd = os.getcwd() files = [RelativePath(repo.root + '/' + f, cwd) for f in files] try: cmd = ["gofmt", "-l"] if not opts["list"]: cmd += ["-w"] if os.spawnvp(os.P_WAIT, "gofmt", cmd + files) != 0: raise hg_util.Abort("gofmt did not exit cleanly") except hg_error.Abort, e: raise except: raise hg_util.Abort("gofmt: " + ExceptionDetail()) return def gofmt_required(files): return [f for f in files if (not f.startswith('test/') or f.startswith('test/bench/')) and f.endswith('.go')] ####################################################################### # hg mail @hgcommand def mail(ui, repo, *pats, **opts): """mail a change for review Uploads a patch to the code review server and then sends mail to the reviewer and CC list asking for a review. """ if codereview_disabled: return codereview_disabled cl, err = CommandLineCL(ui, repo, pats, opts, defaultcc=defaultcc) if err != "": return err cl.Upload(ui, repo, gofmt_just_warn=True) if not cl.reviewer: # If no reviewer is listed, assign the review to defaultcc. # This makes sure that it appears in the # codereview.appspot.com/user/defaultcc # page, so that it doesn't get dropped on the floor. if not defaultcc: return "no reviewers listed in CL" cl.cc = Sub(cl.cc, defaultcc) cl.reviewer = defaultcc cl.Flush(ui, repo) if cl.files == []: return "no changed files, not sending mail" cl.Mail(ui, repo) ####################################################################### # hg p / hg pq / hg ps / hg pending @hgcommand def ps(ui, repo, *pats, **opts): """alias for hg p --short """ opts['short'] = True return pending(ui, repo, *pats, **opts) @hgcommand def pq(ui, repo, *pats, **opts): """alias for hg p --quick """ opts['quick'] = True return pending(ui, repo, *pats, **opts) @hgcommand def pending(ui, repo, *pats, **opts): """show pending changes Lists pending changes followed by a list of unassigned but modified files. """ if codereview_disabled: return codereview_disabled quick = opts.get('quick', False) short = opts.get('short', False) m = LoadAllCL(ui, repo, web=not quick and not short) names = m.keys() names.sort() for name in names: cl = m[name] if short: ui.write(name + "\t" + line1(cl.desc) + "\n") else: ui.write(cl.PendingText(quick=quick) + "\n") if short: return files = DefaultFiles(ui, repo, []) if len(files) > 0: s = "Changed files not in any CL:\n" for f in files: s += "\t" + f + "\n" ui.write(s) ####################################################################### # hg submit def need_sync(): raise hg_util.Abort("local repository out of date; must sync before submit") @hgcommand def submit(ui, repo, *pats, **opts): """submit change to remote repository Submits change to remote repository. Bails out if the local repository is not in sync with the remote one. """ if codereview_disabled: return codereview_disabled # We already called this on startup but sometimes Mercurial forgets. set_mercurial_encoding_to_utf8() if not opts["no_incoming"] and hg_incoming(ui, repo): need_sync() cl, err = CommandLineCL(ui, repo, pats, opts, defaultcc=defaultcc) if err != "": return err user = None if cl.copied_from: user = cl.copied_from userline = CheckContributor(ui, repo, user) typecheck(userline, str) about = "" if cl.reviewer: about += "R=" + JoinComma([CutDomain(s) for s in cl.reviewer]) + "\n" if opts.get('tbr'): tbr = SplitCommaSpace(opts.get('tbr')) cl.reviewer = Add(cl.reviewer, tbr) about += "TBR=" + JoinComma([CutDomain(s) for s in tbr]) + "\n" if cl.cc: about += "CC=" + JoinComma([CutDomain(s) for s in cl.cc]) + "\n" if not cl.reviewer: return "no reviewers listed in CL" if not cl.local: return "cannot submit non-local CL" # upload, to sync current patch and also get change number if CL is new. if not cl.copied_from: cl.Upload(ui, repo, gofmt_just_warn=True) # check gofmt for real; allowed upload to warn in order to save CL. cl.Flush(ui, repo) CheckFormat(ui, repo, cl.files) about += "%s%s\n" % (server_url_base, cl.name) if cl.copied_from: about += "\nCommitter: " + CheckContributor(ui, repo, None) + "\n" typecheck(about, str) if not cl.mailed and not cl.copied_from: # in case this is TBR cl.Mail(ui, repo) # submit changes locally message = cl.desc.rstrip() + "\n\n" + about typecheck(message, str) set_status("pushing " + cl.name + " to remote server") if hg_outgoing(ui, repo): raise hg_util.Abort("local repository corrupt or out-of-phase with remote: found outgoing changes") old_heads = len(hg_heads(ui, repo).split()) global commit_okay commit_okay = True ret = hg_commit(ui, repo, *['path:'+f for f in cl.files], message=message, user=userline) commit_okay = False if ret: return "nothing changed" node = repo["-1"].node() # push to remote; if it fails for any reason, roll back try: new_heads = len(hg_heads(ui, repo).split()) if old_heads != new_heads and not (old_heads == 0 and new_heads == 1): # Created new head, so we weren't up to date. need_sync() # Push changes to remote. If it works, we're committed. If not, roll back. try: hg_push(ui, repo) except hg_error.Abort, e: if e.message.find("push creates new heads") >= 0: # Remote repository had changes we missed. need_sync() raise except: real_rollback() raise # We're committed. Upload final patch, close review, add commit message. changeURL = hg_node.short(node) url = ui.expandpath("default") m = re.match("(^https?://([^@/]+@)?([^.]+)\.googlecode\.com/hg/?)" + "|" + "(^https?://([^@/]+@)?code\.google\.com/p/([^/.]+)(\.[^./]+)?/?)", url) if m: if m.group(1): # prj.googlecode.com/hg/ case changeURL = "http://code.google.com/p/%s/source/detail?r=%s" % (m.group(3), changeURL) elif m.group(4) and m.group(7): # code.google.com/p/prj.subrepo/ case changeURL = "http://code.google.com/p/%s/source/detail?r=%s&repo=%s" % (m.group(6), changeURL, m.group(7)[1:]) elif m.group(4): # code.google.com/p/prj/ case changeURL = "http://code.google.com/p/%s/source/detail?r=%s" % (m.group(6), changeURL) else: print >>sys.stderr, "URL: ", url else: print >>sys.stderr, "URL: ", url pmsg = "*** Submitted as " + changeURL + " ***\n\n" + message # When posting, move reviewers to CC line, # so that the issue stops showing up in their "My Issues" page. PostMessage(ui, cl.name, pmsg, reviewers="", cc=JoinComma(cl.reviewer+cl.cc)) if not cl.copied_from: EditDesc(cl.name, closed=True, private=cl.private) cl.Delete(ui, repo) c = repo[None] if c.branch() == releaseBranch and not c.modified() and not c.added() and not c.removed(): ui.write("switching from %s to default branch.\n" % releaseBranch) err = hg_clean(repo, "default") if err: return err return None ####################################################################### # hg sync @hgcommand def sync(ui, repo, **opts): """synchronize with remote repository Incorporates recent changes from the remote repository into the local repository. """ if codereview_disabled: return codereview_disabled if not opts["local"]: err = hg_pull(ui, repo, update=True) if err: return err sync_changes(ui, repo) def sync_changes(ui, repo): # Look through recent change log descriptions to find # potential references to http://.*/our-CL-number. # Double-check them by looking at the Rietveld log. for rev in hg_log(ui, repo, limit=100, template="{node}\n").split(): desc = repo[rev].description().strip() for clname in re.findall('(?m)^http://(?:[^\n]+)/([0-9]+)$', desc): if IsLocalCL(ui, repo, clname) and IsRietveldSubmitted(ui, clname, repo[rev].hex()): ui.warn("CL %s submitted as %s; closing\n" % (clname, repo[rev])) cl, err = LoadCL(ui, repo, clname, web=False) if err != "": ui.warn("loading CL %s: %s\n" % (clname, err)) continue if not cl.copied_from: EditDesc(cl.name, closed=True, private=cl.private) cl.Delete(ui, repo) # Remove files that are not modified from the CLs in which they appear. all = LoadAllCL(ui, repo, web=False) changed = ChangedFiles(ui, repo, []) for cl in all.values(): extra = Sub(cl.files, changed) if extra: ui.warn("Removing unmodified files from CL %s:\n" % (cl.name,)) for f in extra: ui.warn("\t%s\n" % (f,)) cl.files = Sub(cl.files, extra) cl.Flush(ui, repo) if not cl.files: if not cl.copied_from: ui.warn("CL %s has no files; delete (abandon) with hg change -d %s\n" % (cl.name, cl.name)) else: ui.warn("CL %s has no files; delete locally with hg change -D %s\n" % (cl.name, cl.name)) return ####################################################################### # hg upload @hgcommand def upload(ui, repo, name, **opts): """upload diffs to the code review server Uploads the current modifications for a given change to the server. """ if codereview_disabled: return codereview_disabled repo.ui.quiet = True cl, err = LoadCL(ui, repo, name, web=True) if err != "": return err if not cl.local: return "cannot upload non-local change" cl.Upload(ui, repo) print "%s%s\n" % (server_url_base, cl.name) return ####################################################################### # Table of commands, supplied to Mercurial for installation. review_opts = [ ('r', 'reviewer', '', 'add reviewer'), ('', 'cc', '', 'add cc'), ('', 'tbr', '', 'add future reviewer'), ('m', 'message', '', 'change description (for new change)'), ] cmdtable = { # The ^ means to show this command in the help text that # is printed when running hg with no arguments. "^change": ( change, [ ('d', 'delete', None, 'delete existing change list'), ('D', 'deletelocal', None, 'delete locally, but do not change CL on server'), ('i', 'stdin', None, 'read change list from standard input'), ('o', 'stdout', None, 'print change list to standard output'), ('p', 'pending', None, 'print pending summary to standard output'), ], "[-d | -D] [-i] [-o] change# or FILE ..." ), "^clpatch": ( clpatch, [ ('', 'ignore_hgpatch_failure', None, 'create CL metadata even if hgpatch fails'), ('', 'no_incoming', None, 'disable check for incoming changes'), ], "change#" ), # Would prefer to call this codereview-login, but then # hg help codereview prints the help for this command # instead of the help for the extension. "code-login": ( code_login, [], "", ), "^download": ( download, [], "change#" ), "^file": ( file, [ ('d', 'delete', None, 'delete files from change list (but not repository)'), ], "[-d] change# FILE ..." ), "^gofmt": ( gofmt, [ ('l', 'list', None, 'list files that would change, but do not edit them'), ], "FILE ..." ), "^pending|p": ( pending, [ ('s', 'short', False, 'show short result form'), ('', 'quick', False, 'do not consult codereview server'), ], "[FILE ...]" ), "^ps": ( ps, [], "[FILE ...]" ), "^pq": ( pq, [], "[FILE ...]" ), "^mail": ( mail, review_opts + [ ] + hg_commands.walkopts, "[-r reviewer] [--cc cc] [change# | file ...]" ), "^release-apply": ( release_apply, [ ('', 'ignore_hgpatch_failure', None, 'create CL metadata even if hgpatch fails'), ('', 'no_incoming', None, 'disable check for incoming changes'), ], "change#" ), # TODO: release-start, release-tag, weekly-tag "^submit": ( submit, review_opts + [ ('', 'no_incoming', None, 'disable initial incoming check (for testing)'), ] + hg_commands.walkopts + hg_commands.commitopts + hg_commands.commitopts2, "[-r reviewer] [--cc cc] [change# | file ...]" ), "^sync": ( sync, [ ('', 'local', None, 'do not pull changes from remote repository') ], "[--local]", ), "^undo": ( undo, [ ('', 'ignore_hgpatch_failure', None, 'create CL metadata even if hgpatch fails'), ('', 'no_incoming', None, 'disable check for incoming changes'), ], "change#" ), "^upload": ( upload, [], "change#" ), } ####################################################################### # Mercurial extension initialization def norollback(*pats, **opts): """(disabled when using this extension)""" raise hg_util.Abort("codereview extension enabled; use undo instead of rollback") codereview_init = False def reposetup(ui, repo): global codereview_disabled global defaultcc # reposetup gets called both for the local repository # and also for any repository we are pulling or pushing to. # Only initialize the first time. global codereview_init if codereview_init: return codereview_init = True # Read repository-specific options from lib/codereview/codereview.cfg or codereview.cfg. root = '' try: root = repo.root except: # Yes, repo might not have root; see issue 959. codereview_disabled = 'codereview disabled: repository has no root' return repo_config_path = '' p1 = root + '/lib/codereview/codereview.cfg' p2 = root + '/codereview.cfg' if os.access(p1, os.F_OK): repo_config_path = p1 else: repo_config_path = p2 try: f = open(repo_config_path) for line in f: if line.startswith('defaultcc:'): defaultcc = SplitCommaSpace(line[len('defaultcc:'):]) if line.startswith('contributors:'): global contributorsURL contributorsURL = line[len('contributors:'):].strip() except: codereview_disabled = 'codereview disabled: cannot open ' + repo_config_path return remote = ui.config("paths", "default", "") if remote.find("://") < 0: raise hg_util.Abort("codereview: default path '%s' is not a URL" % (remote,)) InstallMatch(ui, repo) RietveldSetup(ui, repo) # Disable the Mercurial commands that might change the repository. # Only commands in this extension are supposed to do that. ui.setconfig("hooks", "precommit.codereview", precommithook) # Rollback removes an existing commit. Don't do that either. global real_rollback real_rollback = repo.rollback repo.rollback = norollback ####################################################################### # Wrappers around upload.py for interacting with Rietveld from HTMLParser import HTMLParser # HTML form parser class FormParser(HTMLParser): def __init__(self): self.map = {} self.curtag = None self.curdata = None HTMLParser.__init__(self) def handle_starttag(self, tag, attrs): if tag == "input": key = None value = '' for a in attrs: if a[0] == 'name': key = a[1] if a[0] == 'value': value = a[1] if key is not None: self.map[key] = value if tag == "textarea": key = None for a in attrs: if a[0] == 'name': key = a[1] if key is not None: self.curtag = key self.curdata = '' def handle_endtag(self, tag): if tag == "textarea" and self.curtag is not None: self.map[self.curtag] = self.curdata self.curtag = None self.curdata = None def handle_charref(self, name): self.handle_data(unichr(int(name))) def handle_entityref(self, name): import htmlentitydefs if name in htmlentitydefs.entitydefs: self.handle_data(htmlentitydefs.entitydefs[name]) else: self.handle_data("&" + name + ";") def handle_data(self, data): if self.curdata is not None: self.curdata += data def JSONGet(ui, path): try: data = MySend(path, force_auth=False) typecheck(data, str) d = fix_json(json.loads(data)) except: ui.warn("JSONGet %s: %s\n" % (path, ExceptionDetail())) return None return d # Clean up json parser output to match our expectations: # * all strings are UTF-8-encoded str, not unicode. # * missing fields are missing, not None, # so that d.get("foo", defaultvalue) works. def fix_json(x): if type(x) in [str, int, float, bool, type(None)]: pass elif type(x) is unicode: x = x.encode("utf-8") elif type(x) is list: for i in range(len(x)): x[i] = fix_json(x[i]) elif type(x) is dict: todel = [] for k in x: if x[k] is None: todel.append(k) else: x[k] = fix_json(x[k]) for k in todel: del x[k] else: raise hg_util.Abort("unknown type " + str(type(x)) + " in fix_json") if type(x) is str: x = x.replace('\r\n', '\n') return x def IsRietveldSubmitted(ui, clname, hex): dict = JSONGet(ui, "/api/" + clname + "?messages=true") if dict is None: return False for msg in dict.get("messages", []): text = msg.get("text", "") m = re.match('\*\*\* Submitted as [^*]*?([0-9a-f]+) \*\*\*', text) if m is not None and len(m.group(1)) >= 8 and hex.startswith(m.group(1)): return True return False def IsRietveldMailed(cl): for msg in cl.dict.get("messages", []): if msg.get("text", "").find("I'd like you to review this change") >= 0: return True return False def DownloadCL(ui, repo, clname): set_status("downloading CL " + clname) cl, err = LoadCL(ui, repo, clname, web=True) if err != "": return None, None, None, "error loading CL %s: %s" % (clname, err) # Find most recent diff diffs = cl.dict.get("patchsets", []) if not diffs: return None, None, None, "CL has no patch sets" patchid = diffs[-1] patchset = JSONGet(ui, "/api/" + clname + "/" + str(patchid)) if patchset is None: return None, None, None, "error loading CL patchset %s/%d" % (clname, patchid) if patchset.get("patchset", 0) != patchid: return None, None, None, "malformed patchset information" vers = "" msg = patchset.get("message", "").split() if len(msg) >= 3 and msg[0] == "diff" and msg[1] == "-r": vers = msg[2] diff = "/download/issue" + clname + "_" + str(patchid) + ".diff" diffdata = MySend(diff, force_auth=False) # Print warning if email is not in CONTRIBUTORS file. email = cl.dict.get("owner_email", "") if not email: return None, None, None, "cannot find owner for %s" % (clname) him = FindContributor(ui, repo, email) me = FindContributor(ui, repo, None) if him == me: cl.mailed = IsRietveldMailed(cl) else: cl.copied_from = email return cl, vers, diffdata, "" def MySend(request_path, payload=None, content_type="application/octet-stream", timeout=None, force_auth=True, **kwargs): """Run MySend1 maybe twice, because Rietveld is unreliable.""" try: return MySend1(request_path, payload, content_type, timeout, force_auth, **kwargs) except Exception, e: if type(e) != urllib2.HTTPError or e.code != 500: # only retry on HTTP 500 error raise print >>sys.stderr, "Loading "+request_path+": "+ExceptionDetail()+"; trying again in 2 seconds." time.sleep(2) return MySend1(request_path, payload, content_type, timeout, force_auth, **kwargs) # Like upload.py Send but only authenticates when the # redirect is to www.google.com/accounts. This keeps # unnecessary redirects from happening during testing. def MySend1(request_path, payload=None, content_type="application/octet-stream", timeout=None, force_auth=True, **kwargs): """Sends an RPC and returns the response. Args: request_path: The path to send the request to, eg /api/appversion/create. payload: The body of the request, or None to send an empty request. content_type: The Content-Type header to use. timeout: timeout in seconds; default None i.e. no timeout. (Note: for large requests on OS X, the timeout doesn't work right.) kwargs: Any keyword arguments are converted into query string parameters. Returns: The response body, as a string. """ # TODO: Don't require authentication. Let the server say # whether it is necessary. global rpc if rpc == None: rpc = GetRpcServer(upload_options) self = rpc if not self.authenticated and force_auth: self._Authenticate() if request_path is None: return old_timeout = socket.getdefaulttimeout() socket.setdefaulttimeout(timeout) try: tries = 0 while True: tries += 1 args = dict(kwargs) url = "http://%s%s" % (self.host, request_path) if args: url += "?" + urllib.urlencode(args) req = self._CreateRequest(url=url, data=payload) req.add_header("Content-Type", content_type) try: f = self.opener.open(req) response = f.read() f.close() # Translate \r\n into \n, because Rietveld doesn't. response = response.replace('\r\n', '\n') # who knows what urllib will give us if type(response) == unicode: response = response.encode("utf-8") typecheck(response, str) return response except urllib2.HTTPError, e: if tries > 3: raise elif e.code == 401: self._Authenticate() elif e.code == 302: loc = e.info()["location"] if not loc.startswith('https://www.google.com/a') or loc.find('/ServiceLogin') < 0: return '' self._Authenticate() else: raise finally: socket.setdefaulttimeout(old_timeout) def GetForm(url): f = FormParser() f.feed(ustr(MySend(url))) # f.feed wants unicode f.close() # convert back to utf-8 to restore sanity m = {} for k,v in f.map.items(): m[k.encode("utf-8")] = v.replace("\r\n", "\n").encode("utf-8") return m def EditDesc(issue, subject=None, desc=None, reviewers=None, cc=None, closed=False, private=False): set_status("uploading change to description") form_fields = GetForm("/" + issue + "/edit") if subject is not None: form_fields['subject'] = subject if desc is not None: form_fields['description'] = desc if reviewers is not None: form_fields['reviewers'] = reviewers if cc is not None: form_fields['cc'] = cc if closed: form_fields['closed'] = "checked" if private: form_fields['private'] = "checked" ctype, body = EncodeMultipartFormData(form_fields.items(), []) response = MySend("/" + issue + "/edit", body, content_type=ctype) if response != "": print >>sys.stderr, "Error editing description:\n" + "Sent form: \n", form_fields, "\n", response sys.exit(2) def PostMessage(ui, issue, message, reviewers=None, cc=None, send_mail=True, subject=None): set_status("uploading message") form_fields = GetForm("/" + issue + "/publish") if reviewers is not None: form_fields['reviewers'] = reviewers if cc is not None: form_fields['cc'] = cc if send_mail: form_fields['send_mail'] = "checked" else: del form_fields['send_mail'] if subject is not None: form_fields['subject'] = subject form_fields['message'] = message form_fields['message_only'] = '1' # Don't include draft comments if reviewers is not None or cc is not None: form_fields['message_only'] = '' # Must set '' in order to override cc/reviewer ctype = "applications/x-www-form-urlencoded" body = urllib.urlencode(form_fields) response = MySend("/" + issue + "/publish", body, content_type=ctype) if response != "": print response sys.exit(2) class opt(object): pass def RietveldSetup(ui, repo): global force_google_account global rpc global server global server_url_base global upload_options global verbosity if not ui.verbose: verbosity = 0 # Config options. x = ui.config("codereview", "server") if x is not None: server = x # TODO(rsc): Take from ui.username? email = None x = ui.config("codereview", "email") if x is not None: email = x server_url_base = "http://" + server + "/" testing = ui.config("codereview", "testing") force_google_account = ui.configbool("codereview", "force_google_account", False) upload_options = opt() upload_options.email = email upload_options.host = None upload_options.verbose = 0 upload_options.description = None upload_options.description_file = None upload_options.reviewers = None upload_options.cc = None upload_options.message = None upload_options.issue = None upload_options.download_base = False upload_options.revision = None upload_options.send_mail = False upload_options.vcs = None upload_options.server = server upload_options.save_cookies = True if testing: upload_options.save_cookies = False upload_options.email = "test@example.com" rpc = None global releaseBranch tags = repo.branchtags().keys() if 'release-branch.go10' in tags: # NOTE(rsc): This tags.sort is going to get the wrong # answer when comparing release-branch.go9 with # release-branch.go10. It will be a while before we care. raise hg_util.Abort('tags.sort needs to be fixed for release-branch.go10') tags.sort() for t in tags: if t.startswith('release-branch.go'): releaseBranch = t ####################################################################### # http://codereview.appspot.com/static/upload.py, heavily edited. #!/usr/bin/env python # # Copyright 2007 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Tool for uploading diffs from a version control system to the codereview app. Usage summary: upload.py [options] [-- diff_options] Diff options are passed to the diff command of the underlying system. Supported version control systems: Git Mercurial Subversion It is important for Git/Mercurial users to specify a tree/node/branch to diff against by using the '--rev' option. """ # This code is derived from appcfg.py in the App Engine SDK (open source), # and from ASPN recipe #146306. import cookielib import getpass import logging import mimetypes import optparse import os import re import socket import subprocess import sys import urllib import urllib2 import urlparse # The md5 module was deprecated in Python 2.5. try: from hashlib import md5 except ImportError: from md5 import md5 try: import readline except ImportError: pass # The logging verbosity: # 0: Errors only. # 1: Status messages. # 2: Info logs. # 3: Debug logs. verbosity = 1 # Max size of patch or base file. MAX_UPLOAD_SIZE = 900 * 1024 # whitelist for non-binary filetypes which do not start with "text/" # .mm (Objective-C) shows up as application/x-freemind on my Linux box. TEXT_MIMETYPES = [ 'application/javascript', 'application/x-javascript', 'application/x-freemind' ] def GetEmail(prompt): """Prompts the user for their email address and returns it. The last used email address is saved to a file and offered up as a suggestion to the user. If the user presses enter without typing in anything the last used email address is used. If the user enters a new address, it is saved for next time we prompt. """ last_email_file_name = os.path.expanduser("~/.last_codereview_email_address") last_email = "" if os.path.exists(last_email_file_name): try: last_email_file = open(last_email_file_name, "r") last_email = last_email_file.readline().strip("\n") last_email_file.close() prompt += " [%s]" % last_email except IOError, e: pass email = raw_input(prompt + ": ").strip() if email: try: last_email_file = open(last_email_file_name, "w") last_email_file.write(email) last_email_file.close() except IOError, e: pass else: email = last_email return email def StatusUpdate(msg): """Print a status message to stdout. If 'verbosity' is greater than 0, print the message. Args: msg: The string to print. """ if verbosity > 0: print msg def ErrorExit(msg): """Print an error message to stderr and exit.""" print >>sys.stderr, msg sys.exit(1) class ClientLoginError(urllib2.HTTPError): """Raised to indicate there was an error authenticating with ClientLogin.""" def __init__(self, url, code, msg, headers, args): urllib2.HTTPError.__init__(self, url, code, msg, headers, None) self.args = args self.reason = args["Error"] class AbstractRpcServer(object): """Provides a common interface for a simple RPC server.""" def __init__(self, host, auth_function, host_override=None, extra_headers={}, save_cookies=False): """Creates a new HttpRpcServer. Args: host: The host to send requests to. auth_function: A function that takes no arguments and returns an (email, password) tuple when called. Will be called if authentication is required. host_override: The host header to send to the server (defaults to host). extra_headers: A dict of extra headers to append to every request. save_cookies: If True, save the authentication cookies to local disk. If False, use an in-memory cookiejar instead. Subclasses must implement this functionality. Defaults to False. """ self.host = host self.host_override = host_override self.auth_function = auth_function self.authenticated = False self.extra_headers = extra_headers self.save_cookies = save_cookies self.opener = self._GetOpener() if self.host_override: logging.info("Server: %s; Host: %s", self.host, self.host_override) else: logging.info("Server: %s", self.host) def _GetOpener(self): """Returns an OpenerDirector for making HTTP requests. Returns: A urllib2.OpenerDirector object. """ raise NotImplementedError() def _CreateRequest(self, url, data=None): """Creates a new urllib request.""" logging.debug("Creating request for: '%s' with payload:\n%s", url, data) req = urllib2.Request(url, data=data) if self.host_override: req.add_header("Host", self.host_override) for key, value in self.extra_headers.iteritems(): req.add_header(key, value) return req def _GetAuthToken(self, email, password): """Uses ClientLogin to authenticate the user, returning an auth token. Args: email: The user's email address password: The user's password Raises: ClientLoginError: If there was an error authenticating with ClientLogin. HTTPError: If there was some other form of HTTP error. Returns: The authentication token returned by ClientLogin. """ account_type = "GOOGLE" if self.host.endswith(".google.com") and not force_google_account: # Needed for use inside Google. account_type = "HOSTED" req = self._CreateRequest( url="https://www.google.com/accounts/ClientLogin", data=urllib.urlencode({ "Email": email, "Passwd": password, "service": "ah", "source": "rietveld-codereview-upload", "accountType": account_type, }), ) try: response = self.opener.open(req) response_body = response.read() response_dict = dict(x.split("=") for x in response_body.split("\n") if x) return response_dict["Auth"] except urllib2.HTTPError, e: if e.code == 403: body = e.read() response_dict = dict(x.split("=", 1) for x in body.split("\n") if x) raise ClientLoginError(req.get_full_url(), e.code, e.msg, e.headers, response_dict) else: raise def _GetAuthCookie(self, auth_token): """Fetches authentication cookies for an authentication token. Args: auth_token: The authentication token returned by ClientLogin. Raises: HTTPError: If there was an error fetching the authentication cookies. """ # This is a dummy value to allow us to identify when we're successful. continue_location = "http://localhost/" args = {"continue": continue_location, "auth": auth_token} req = self._CreateRequest("http://%s/_ah/login?%s" % (self.host, urllib.urlencode(args))) try: response = self.opener.open(req) except urllib2.HTTPError, e: response = e if (response.code != 302 or response.info()["location"] != continue_location): raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg, response.headers, response.fp) self.authenticated = True def _Authenticate(self): """Authenticates the user. The authentication process works as follows: 1) We get a username and password from the user 2) We use ClientLogin to obtain an AUTH token for the user (see http://code.google.com/apis/accounts/AuthForInstalledApps.html). 3) We pass the auth token to /_ah/login on the server to obtain an authentication cookie. If login was successful, it tries to redirect us to the URL we provided. If we attempt to access the upload API without first obtaining an authentication cookie, it returns a 401 response (or a 302) and directs us to authenticate ourselves with ClientLogin. """ for i in range(3): credentials = self.auth_function() try: auth_token = self._GetAuthToken(credentials[0], credentials[1]) except ClientLoginError, e: if e.reason == "BadAuthentication": print >>sys.stderr, "Invalid username or password." continue if e.reason == "CaptchaRequired": print >>sys.stderr, ( "Please go to\n" "https://www.google.com/accounts/DisplayUnlockCaptcha\n" "and verify you are a human. Then try again.") break if e.reason == "NotVerified": print >>sys.stderr, "Account not verified." break if e.reason == "TermsNotAgreed": print >>sys.stderr, "User has not agreed to TOS." break if e.reason == "AccountDeleted": print >>sys.stderr, "The user account has been deleted." break if e.reason == "AccountDisabled": print >>sys.stderr, "The user account has been disabled." break if e.reason == "ServiceDisabled": print >>sys.stderr, "The user's access to the service has been disabled." break if e.reason == "ServiceUnavailable": print >>sys.stderr, "The service is not available; try again later." break raise self._GetAuthCookie(auth_token) return def Send(self, request_path, payload=None, content_type="application/octet-stream", timeout=None, **kwargs): """Sends an RPC and returns the response. Args: request_path: The path to send the request to, eg /api/appversion/create. payload: The body of the request, or None to send an empty request. content_type: The Content-Type header to use. timeout: timeout in seconds; default None i.e. no timeout. (Note: for large requests on OS X, the timeout doesn't work right.) kwargs: Any keyword arguments are converted into query string parameters. Returns: The response body, as a string. """ # TODO: Don't require authentication. Let the server say # whether it is necessary. if not self.authenticated: self._Authenticate() old_timeout = socket.getdefaulttimeout() socket.setdefaulttimeout(timeout) try: tries = 0 while True: tries += 1 args = dict(kwargs) url = "http://%s%s" % (self.host, request_path) if args: url += "?" + urllib.urlencode(args) req = self._CreateRequest(url=url, data=payload) req.add_header("Content-Type", content_type) try: f = self.opener.open(req) response = f.read() f.close() return response except urllib2.HTTPError, e: if tries > 3: raise elif e.code == 401 or e.code == 302: self._Authenticate() else: raise finally: socket.setdefaulttimeout(old_timeout) class HttpRpcServer(AbstractRpcServer): """Provides a simplified RPC-style interface for HTTP requests.""" def _Authenticate(self): """Save the cookie jar after authentication.""" super(HttpRpcServer, self)._Authenticate() if self.save_cookies: StatusUpdate("Saving authentication cookies to %s" % self.cookie_file) self.cookie_jar.save() def _GetOpener(self): """Returns an OpenerDirector that supports cookies and ignores redirects. Returns: A urllib2.OpenerDirector object. """ opener = urllib2.OpenerDirector() opener.add_handler(urllib2.ProxyHandler()) opener.add_handler(urllib2.UnknownHandler()) opener.add_handler(urllib2.HTTPHandler()) opener.add_handler(urllib2.HTTPDefaultErrorHandler()) opener.add_handler(urllib2.HTTPSHandler()) opener.add_handler(urllib2.HTTPErrorProcessor()) if self.save_cookies: self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies_" + server) self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file) if os.path.exists(self.cookie_file): try: self.cookie_jar.load() self.authenticated = True StatusUpdate("Loaded authentication cookies from %s" % self.cookie_file) except (cookielib.LoadError, IOError): # Failed to load cookies - just ignore them. pass else: # Create an empty cookie file with mode 600 fd = os.open(self.cookie_file, os.O_CREAT, 0600) os.close(fd) # Always chmod the cookie file os.chmod(self.cookie_file, 0600) else: # Don't save cookies across runs of update.py. self.cookie_jar = cookielib.CookieJar() opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar)) return opener def GetRpcServer(options): """Returns an instance of an AbstractRpcServer. Returns: A new AbstractRpcServer, on which RPC calls can be made. """ rpc_server_class = HttpRpcServer def GetUserCredentials(): """Prompts the user for a username and password.""" # Disable status prints so they don't obscure the password prompt. global global_status st = global_status global_status = None email = options.email if email is None: email = GetEmail("Email (login for uploading to %s)" % options.server) password = getpass.getpass("Password for %s: " % email) # Put status back. global_status = st return (email, password) # If this is the dev_appserver, use fake authentication. host = (options.host or options.server).lower() if host == "localhost" or host.startswith("localhost:"): email = options.email if email is None: email = "test@example.com" logging.info("Using debug user %s. Override with --email" % email) server = rpc_server_class( options.server, lambda: (email, "password"), host_override=options.host, extra_headers={"Cookie": 'dev_appserver_login="%s:False"' % email}, save_cookies=options.save_cookies) # Don't try to talk to ClientLogin. server.authenticated = True return server return rpc_server_class(options.server, GetUserCredentials, host_override=options.host, save_cookies=options.save_cookies) def EncodeMultipartFormData(fields, files): """Encode form fields for multipart/form-data. Args: fields: A sequence of (name, value) elements for regular form fields. files: A sequence of (name, filename, value) elements for data to be uploaded as files. Returns: (content_type, body) ready for httplib.HTTP instance. Source: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306 """ BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-' CRLF = '\r\n' lines = [] for (key, value) in fields: typecheck(key, str) typecheck(value, str) lines.append('--' + BOUNDARY) lines.append('Content-Disposition: form-data; name="%s"' % key) lines.append('') lines.append(value) for (key, filename, value) in files: typecheck(key, str) typecheck(filename, str) typecheck(value, str) lines.append('--' + BOUNDARY) lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename)) lines.append('Content-Type: %s' % GetContentType(filename)) lines.append('') lines.append(value) lines.append('--' + BOUNDARY + '--') lines.append('') body = CRLF.join(lines) content_type = 'multipart/form-data; boundary=%s' % BOUNDARY return content_type, body def GetContentType(filename): """Helper to guess the content-type from the filename.""" return mimetypes.guess_type(filename)[0] or 'application/octet-stream' # Use a shell for subcommands on Windows to get a PATH search. use_shell = sys.platform.startswith("win") def RunShellWithReturnCode(command, print_output=False, universal_newlines=True, env=os.environ): """Executes a command and returns the output from stdout and the return code. Args: command: Command to execute. print_output: If True, the output is printed to stdout. If False, both stdout and stderr are ignored. universal_newlines: Use universal_newlines flag (default: True). Returns: Tuple (output, return code) """ logging.info("Running %s", command) p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=use_shell, universal_newlines=universal_newlines, env=env) if print_output: output_array = [] while True: line = p.stdout.readline() if not line: break print line.strip("\n") output_array.append(line) output = "".join(output_array) else: output = p.stdout.read() p.wait() errout = p.stderr.read() if print_output and errout: print >>sys.stderr, errout p.stdout.close() p.stderr.close() return output, p.returncode def RunShell(command, silent_ok=False, universal_newlines=True, print_output=False, env=os.environ): data, retcode = RunShellWithReturnCode(command, print_output, universal_newlines, env) if retcode: ErrorExit("Got error status from %s:\n%s" % (command, data)) if not silent_ok and not data: ErrorExit("No output from %s" % command) return data class VersionControlSystem(object): """Abstract base class providing an interface to the VCS.""" def __init__(self, options): """Constructor. Args: options: Command line options. """ self.options = options def GenerateDiff(self, args): """Return the current diff as a string. Args: args: Extra arguments to pass to the diff command. """ raise NotImplementedError( "abstract method -- subclass %s must override" % self.__class__) def GetUnknownFiles(self): """Return a list of files unknown to the VCS.""" raise NotImplementedError( "abstract method -- subclass %s must override" % self.__class__) def CheckForUnknownFiles(self): """Show an "are you sure?" prompt if there are unknown files.""" unknown_files = self.GetUnknownFiles() if unknown_files: print "The following files are not added to version control:" for line in unknown_files: print line prompt = "Are you sure to continue?(y/N) " answer = raw_input(prompt).strip() if answer != "y": ErrorExit("User aborted") def GetBaseFile(self, filename): """Get the content of the upstream version of a file. Returns: A tuple (base_content, new_content, is_binary, status) base_content: The contents of the base file. new_content: For text files, this is empty. For binary files, this is the contents of the new file, since the diff output won't contain information to reconstruct the current file. is_binary: True iff the file is binary. status: The status of the file. """ raise NotImplementedError( "abstract method -- subclass %s must override" % self.__class__) def GetBaseFiles(self, diff): """Helper that calls GetBase file for each file in the patch. Returns: A dictionary that maps from filename to GetBaseFile's tuple. Filenames are retrieved based on lines that start with "Index:" or "Property changes on:". """ files = {} for line in diff.splitlines(True): if line.startswith('Index:') or line.startswith('Property changes on:'): unused, filename = line.split(':', 1) # On Windows if a file has property changes its filename uses '\' # instead of '/'. filename = to_slash(filename.strip()) files[filename] = self.GetBaseFile(filename) return files def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options, files): """Uploads the base files (and if necessary, the current ones as well).""" def UploadFile(filename, file_id, content, is_binary, status, is_base): """Uploads a file to the server.""" set_status("uploading " + filename) file_too_large = False if is_base: type = "base" else: type = "current" if len(content) > MAX_UPLOAD_SIZE: print ("Not uploading the %s file for %s because it's too large." % (type, filename)) file_too_large = True content = "" checksum = md5(content).hexdigest() if options.verbose > 0 and not file_too_large: print "Uploading %s file for %s" % (type, filename) url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id) form_fields = [ ("filename", filename), ("status", status), ("checksum", checksum), ("is_binary", str(is_binary)), ("is_current", str(not is_base)), ] if file_too_large: form_fields.append(("file_too_large", "1")) if options.email: form_fields.append(("user", options.email)) ctype, body = EncodeMultipartFormData(form_fields, [("data", filename, content)]) response_body = rpc_server.Send(url, body, content_type=ctype) if not response_body.startswith("OK"): StatusUpdate(" --> %s" % response_body) sys.exit(1) # Don't want to spawn too many threads, nor do we want to # hit Rietveld too hard, or it will start serving 500 errors. # When 8 works, it's no better than 4, and sometimes 8 is # too many for Rietveld to handle. MAX_PARALLEL_UPLOADS = 4 sema = threading.BoundedSemaphore(MAX_PARALLEL_UPLOADS) upload_threads = [] finished_upload_threads = [] class UploadFileThread(threading.Thread): def __init__(self, args): threading.Thread.__init__(self) self.args = args def run(self): UploadFile(*self.args) finished_upload_threads.append(self) sema.release() def StartUploadFile(*args): sema.acquire() while len(finished_upload_threads) > 0: t = finished_upload_threads.pop() upload_threads.remove(t) t.join() t = UploadFileThread(args) upload_threads.append(t) t.start() def WaitForUploads(): for t in upload_threads: t.join() patches = dict() [patches.setdefault(v, k) for k, v in patch_list] for filename in patches.keys(): base_content, new_content, is_binary, status = files[filename] file_id_str = patches.get(filename) if file_id_str.find("nobase") != -1: base_content = None file_id_str = file_id_str[file_id_str.rfind("_") + 1:] file_id = int(file_id_str) if base_content != None: StartUploadFile(filename, file_id, base_content, is_binary, status, True) if new_content != None: StartUploadFile(filename, file_id, new_content, is_binary, status, False) WaitForUploads() def IsImage(self, filename): """Returns true if the filename has an image extension.""" mimetype = mimetypes.guess_type(filename)[0] if not mimetype: return False return mimetype.startswith("image/") def IsBinary(self, filename): """Returns true if the guessed mimetyped isnt't in text group.""" mimetype = mimetypes.guess_type(filename)[0] if not mimetype: return False # e.g. README, "real" binaries usually have an extension # special case for text files which don't start with text/ if mimetype in TEXT_MIMETYPES: return False return not mimetype.startswith("text/") class FakeMercurialUI(object): def __init__(self): self.quiet = True self.output = '' def write(self, *args, **opts): self.output += ' '.join(args) def copy(self): return self def status(self, *args, **opts): pass def formatter(self, topic, opts): from mercurial.formatter import plainformatter return plainformatter(self, topic, opts) def readconfig(self, *args, **opts): pass def expandpath(self, *args, **opts): return global_ui.expandpath(*args, **opts) def configitems(self, *args, **opts): return global_ui.configitems(*args, **opts) def config(self, *args, **opts): return global_ui.config(*args, **opts) use_hg_shell = False # set to True to shell out to hg always; slower class MercurialVCS(VersionControlSystem): """Implementation of the VersionControlSystem interface for Mercurial.""" def __init__(self, options, ui, repo): super(MercurialVCS, self).__init__(options) self.ui = ui self.repo = repo self.status = None # Absolute path to repository (we can be in a subdir) self.repo_dir = os.path.normpath(repo.root) # Compute the subdir cwd = os.path.normpath(os.getcwd()) assert cwd.startswith(self.repo_dir) self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/") if self.options.revision: self.base_rev = self.options.revision else: mqparent, err = RunShellWithReturnCode(['hg', 'log', '--rev', 'qparent', '--template={node}']) if not err and mqparent != "": self.base_rev = mqparent else: out = RunShell(["hg", "parents", "-q"], silent_ok=True).strip() if not out: # No revisions; use 0 to mean a repository with nothing. out = "0:0" self.base_rev = out.split(':')[1].strip() def _GetRelPath(self, filename): """Get relative path of a file according to the current directory, given its logical path in the repo.""" assert filename.startswith(self.subdir), (filename, self.subdir) return filename[len(self.subdir):].lstrip(r"\/") def GenerateDiff(self, extra_args): # If no file specified, restrict to the current subdir extra_args = extra_args or ["."] cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args data = RunShell(cmd, silent_ok=True) svndiff = [] filecount = 0 for line in data.splitlines(): m = re.match("diff --git a/(\S+) b/(\S+)", line) if m: # Modify line to make it look like as it comes from svn diff. # With this modification no changes on the server side are required # to make upload.py work with Mercurial repos. # NOTE: for proper handling of moved/copied files, we have to use # the second filename. filename = m.group(2) svndiff.append("Index: %s" % filename) svndiff.append("=" * 67) filecount += 1 logging.info(line) else: svndiff.append(line) if not filecount: ErrorExit("No valid patches found in output from hg diff") return "\n".join(svndiff) + "\n" def GetUnknownFiles(self): """Return a list of files unknown to the VCS.""" args = [] status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."], silent_ok=True) unknown_files = [] for line in status.splitlines(): st, fn = line.split(" ", 1) if st == "?": unknown_files.append(fn) return unknown_files def get_hg_status(self, rev, path): # We'd like to use 'hg status -C path', but that is buggy # (see http://mercurial.selenic.com/bts/issue3023). # Instead, run 'hg status -C' without a path # and skim the output for the path we want. if self.status is None: if use_hg_shell: out = RunShell(["hg", "status", "-C", "--rev", rev]) else: fui = FakeMercurialUI() ret = hg_commands.status(fui, self.repo, *[], **{'rev': [rev], 'copies': True}) if ret: raise hg_util.Abort(ret) out = fui.output self.status = out.splitlines() for i in range(len(self.status)): # line is # A path # M path # etc line = to_slash(self.status[i]) if line[2:] == path: if i+1 < len(self.status) and self.status[i+1][:2] == ' ': return self.status[i:i+2] return self.status[i:i+1] raise hg_util.Abort("no status for " + path) def GetBaseFile(self, filename): set_status("inspecting " + filename) # "hg status" and "hg cat" both take a path relative to the current subdir # rather than to the repo root, but "hg diff" has given us the full path # to the repo root. base_content = "" new_content = None is_binary = False oldrelpath = relpath = self._GetRelPath(filename) out = self.get_hg_status(self.base_rev, relpath) status, what = out[0].split(' ', 1) if len(out) > 1 and status == "A" and what == relpath: oldrelpath = out[1].strip() status = "M" if ":" in self.base_rev: base_rev = self.base_rev.split(":", 1)[0] else: base_rev = self.base_rev if status != "A": if use_hg_shell: base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath], silent_ok=True) else: base_content = str(self.repo[base_rev][oldrelpath].data()) is_binary = "\0" in base_content # Mercurial's heuristic if status != "R": new_content = open(relpath, "rb").read() is_binary = is_binary or "\0" in new_content if is_binary and base_content and use_hg_shell: # Fetch again without converting newlines base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath], silent_ok=True, universal_newlines=False) if not is_binary or not self.IsImage(relpath): new_content = None return base_content, new_content, is_binary, status # NOTE: The SplitPatch function is duplicated in engine.py, keep them in sync. def SplitPatch(data): """Splits a patch into separate pieces for each file. Args: data: A string containing the output of svn diff. Returns: A list of 2-tuple (filename, text) where text is the svn diff output pertaining to filename. """ patches = [] filename = None diff = [] for line in data.splitlines(True): new_filename = None if line.startswith('Index:'): unused, new_filename = line.split(':', 1) new_filename = new_filename.strip() elif line.startswith('Property changes on:'): unused, temp_filename = line.split(':', 1) # When a file is modified, paths use '/' between directories, however # when a property is modified '\' is used on Windows. Make them the same # otherwise the file shows up twice. temp_filename = to_slash(temp_filename.strip()) if temp_filename != filename: # File has property changes but no modifications, create a new diff. new_filename = temp_filename if new_filename: if filename and diff: patches.append((filename, ''.join(diff))) filename = new_filename diff = [line] continue if diff is not None: diff.append(line) if filename and diff: patches.append((filename, ''.join(diff))) return patches def UploadSeparatePatches(issue, rpc_server, patchset, data, options): """Uploads a separate patch for each file in the diff output. Returns a list of [patch_key, filename] for each file. """ patches = SplitPatch(data) rv = [] for patch in patches: set_status("uploading patch for " + patch[0]) if len(patch[1]) > MAX_UPLOAD_SIZE: print ("Not uploading the patch for " + patch[0] + " because the file is too large.") continue form_fields = [("filename", patch[0])] if not options.download_base: form_fields.append(("content_upload", "1")) files = [("data", "data.diff", patch[1])] ctype, body = EncodeMultipartFormData(form_fields, files) url = "/%d/upload_patch/%d" % (int(issue), int(patchset)) print "Uploading patch for " + patch[0] response_body = rpc_server.Send(url, body, content_type=ctype) lines = response_body.splitlines() if not lines or lines[0] != "OK": StatusUpdate(" --> %s" % response_body) sys.exit(1) rv.append([lines[1], patch[0]]) return rv drawterm-20170818/libauth/000077500000000000000000000000001314554504700152535ustar00rootroot00000000000000drawterm-20170818/libauth/Makefile000066400000000000000000000004621314554504700167150ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libauth.a OFILES=\ attr.$O\ auth_attr.$O\ auth_challenge.$O\ auth_getuserpasswd.$O\ auth_proxy.$O\ auth_respond.$O\ auth_rpc.$O\ auth_userpasswd.$O\ default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/libauth/attr.c000066400000000000000000000054511314554504700163760ustar00rootroot00000000000000#include #include #include int _attrfmt(Fmt *fmt) { char *b, buf[1024], *ebuf; Attr *a; ebuf = buf+sizeof buf; b = buf; strcpy(buf, " "); for(a=va_arg(fmt->args, Attr*); a; a=a->next){ if(a->name == nil) continue; switch(a->type){ case AttrQuery: b = seprint(b, ebuf, " %q?", a->name); break; case AttrNameval: b = seprint(b, ebuf, " %q=%q", a->name, a->val); break; case AttrDefault: b = seprint(b, ebuf, " %q:=%q", a->name, a->val); break; } } return fmtstrcpy(fmt, buf+1); } Attr* _copyattr(Attr *a) { Attr **la, *na; na = nil; la = &na; for(; a; a=a->next){ *la = _mkattr(a->type, a->name, a->val, nil); setmalloctag(*la, getcallerpc(&a)); la = &(*la)->next; } *la = nil; return na; } Attr* _delattr(Attr *a, char *name) { Attr *fa; Attr **la; for(la=&a; *la; ){ if(strcmp((*la)->name, name) == 0){ fa = *la; *la = (*la)->next; fa->next = nil; _freeattr(fa); }else la=&(*la)->next; } return a; } Attr* _findattr(Attr *a, char *n) { for(; a; a=a->next) if(strcmp(a->name, n) == 0 && a->type != AttrQuery) return a; return nil; } void _freeattr(Attr *a) { Attr *anext; for(; a; a=anext){ anext = a->next; free(a->name); free(a->val); a->name = (void*)~0; a->val = (void*)~0; a->next = (void*)~0; free(a); } } Attr* _mkattr(int type, char *name, char *val, Attr *next) { Attr *a; a = malloc(sizeof(*a)); if(a==nil) sysfatal("_mkattr malloc: %r"); a->type = type; a->name = strdup(name); a->val = strdup(val); if(a->name==nil || a->val==nil) sysfatal("_mkattr malloc: %r"); a->next = next; setmalloctag(a, getcallerpc(&type)); return a; } static Attr* cleanattr(Attr *a) { Attr *fa; Attr **la; for(la=&a; *la; ){ if((*la)->type==AttrQuery && _findattr(a, (*la)->name)){ fa = *la; *la = (*la)->next; fa->next = nil; _freeattr(fa); }else la=&(*la)->next; } return a; } Attr* _parseattr(char *s) { char *p, *t, *tok[256]; int i, ntok, type; Attr *a; s = strdup(s); if(s == nil) sysfatal("_parseattr strdup: %r"); ntok = tokenize(s, tok, nelem(tok)); a = nil; for(i=ntok-1; i>=0; i--){ t = tok[i]; if((p = strchr(t, '='))){ *p++ = '\0'; // if(p-2 >= t && p[-2] == ':'){ // p[-2] = '\0'; // type = AttrDefault; // }else type = AttrNameval; a = _mkattr(type, t, p, a); setmalloctag(a, getcallerpc(&s)); } else if(t[strlen(t)-1] == '?'){ t[strlen(t)-1] = '\0'; a = _mkattr(AttrQuery, t, "", a); setmalloctag(a, getcallerpc(&s)); }else{ /* really a syntax error, but better to provide some indication */ a = _mkattr(AttrNameval, t, "", a); setmalloctag(a, getcallerpc(&s)); } } free(s); return cleanattr(a); } char* _strfindattr(Attr *a, char *n) { a = _findattr(a, n); if(a == nil) return nil; return a->val; } drawterm-20170818/libauth/auth_attr.c000066400000000000000000000003311314554504700174070ustar00rootroot00000000000000#include #include #include #include #include "authlocal.h" Attr* auth_attr(AuthRpc *rpc) { if(auth_rpc(rpc, "attr", nil, 0) != ARok) return nil; return _parseattr(rpc->arg); } drawterm-20170818/libauth/auth_challenge.c000066400000000000000000000036701314554504700203700ustar00rootroot00000000000000#include #include #include #include #include "authlocal.h" Chalstate* auth_challenge(char *fmt, ...) { char *p; va_list arg; Chalstate *c; quotefmtinstall(); /* just in case */ va_start(arg, fmt); p = vsmprint(fmt, arg); va_end(arg); if(p == nil) return nil; c = mallocz(sizeof(*c), 1); if(c == nil){ free(p); return nil; } if((c->afd = open("/mnt/factotum/rpc", ORDWR)) < 0){ Error: auth_freechal(c); free(p); return nil; } if((c->rpc=auth_allocrpc(c->afd)) == nil || auth_rpc(c->rpc, "start", p, strlen(p)) != ARok || auth_rpc(c->rpc, "read", nil, 0) != ARok) goto Error; if(c->rpc->narg > sizeof(c->chal)-1){ werrstr("buffer too small for challenge"); goto Error; } memmove(c->chal, c->rpc->arg, c->rpc->narg); c->nchal = c->rpc->narg; free(p); return c; } AuthInfo* auth_response(Chalstate *c) { int ret; AuthInfo *ai; ai = nil; if(c->afd < 0){ werrstr("auth_response: connection not open"); return nil; } if(c->resp == nil){ werrstr("auth_response: nil response"); return nil; } if(c->nresp == 0){ werrstr("auth_response: unspecified response length"); return nil; } if(c->user){ if(auth_rpc(c->rpc, "write", c->user, strlen(c->user)) != ARok){ /* * if this fails we're out of phase with factotum. * give up. */ goto Out; } } if(auth_rpc(c->rpc, "write", c->resp, c->nresp) != ARok){ /* * don't close the connection -- maybe we'll try again. */ return nil; } switch(ret = auth_rpc(c->rpc, "read", nil, 0)){ case ARok: default: werrstr("factotum protocol botch %d %s", ret, c->rpc->ibuf); break; case ARdone: ai = auth_getinfo(c->rpc); break; } Out: close(c->afd); auth_freerpc(c->rpc); c->afd = -1; c->rpc = nil; return ai; } void auth_freechal(Chalstate *c) { if(c == nil) return; if(c->afd >= 0) close(c->afd); if(c->rpc != nil) auth_freerpc(c->rpc); memset(c, 0xBB, sizeof(*c)); free(c); } drawterm-20170818/libauth/auth_getuserpasswd.c000066400000000000000000000025211314554504700213400ustar00rootroot00000000000000#include #include #include #include "authlocal.h" enum { ARgiveup = 100, }; static int dorpc(AuthRpc *rpc, char *verb, char *val, int len, AuthGetkey *getkey) { int ret; for(;;){ if((ret = auth_rpc(rpc, verb, val, len)) != ARneedkey && ret != ARbadkey) return ret; if(getkey == 0) return ARgiveup; /* don't know how */ if((*getkey)(rpc->arg) < 0) return ARgiveup; /* user punted */ } } UserPasswd* auth_getuserpasswd(AuthGetkey *getkey, char *fmt, ...) { AuthRpc *rpc; char *f[3], *p, *params; int fd; va_list arg; UserPasswd *up; up = nil; rpc = nil; params = nil; fd = open("/mnt/factotum/rpc", ORDWR); if(fd < 0) goto out; rpc = auth_allocrpc(fd); if(rpc == nil) goto out; quotefmtinstall(); /* just in case */ va_start(arg, fmt); params = vsmprint(fmt, arg); va_end(arg); if(params == nil) goto out; if(dorpc(rpc, "start", params, strlen(params), getkey) != ARok || dorpc(rpc, "read", nil, 0, getkey) != ARok) goto out; rpc->arg[rpc->narg] = '\0'; if(tokenize(rpc->arg, f, 2) != 2){ werrstr("bad answer from factotum"); goto out; } up = malloc(sizeof(*up)+rpc->narg+1); if(up == nil) goto out; p = (char*)&up[1]; strcpy(p, f[0]); up->user = p; p += strlen(p)+1; strcpy(p, f[1]); up->passwd = p; out: free(params); auth_freerpc(rpc); close(fd); return up; } drawterm-20170818/libauth/auth_proxy.c000066400000000000000000000070361314554504700176270ustar00rootroot00000000000000#include #include #include #include #include "authlocal.h" enum { ARgiveup = 100, }; static uchar* gstring(uchar *p, uchar *ep, char **s) { uint n; if(p == nil) return nil; if(p+BIT16SZ > ep) return nil; n = GBIT16(p); p += BIT16SZ; if(p+n > ep) return nil; *s = malloc(n+1); memmove((*s), p, n); (*s)[n] = '\0'; p += n; return p; } static uchar* gcarray(uchar *p, uchar *ep, uchar **s, int *np) { uint n; if(p == nil) return nil; if(p+BIT16SZ > ep) return nil; n = GBIT16(p); p += BIT16SZ; if(p+n > ep) return nil; *s = malloc(n); if(*s == nil) return nil; memmove((*s), p, n); *np = n; p += n; return p; } void auth_freeAI(AuthInfo *ai) { if(ai == nil) return; free(ai->cuid); free(ai->suid); free(ai->cap); free(ai->secret); free(ai); } static uchar* convM2AI(uchar *p, int n, AuthInfo **aip) { uchar *e = p+n; AuthInfo *ai; ai = mallocz(sizeof(*ai), 1); if(ai == nil) return nil; p = gstring(p, e, &ai->cuid); p = gstring(p, e, &ai->suid); p = gstring(p, e, &ai->cap); p = gcarray(p, e, &ai->secret, &ai->nsecret); if(p == nil) auth_freeAI(ai); else *aip = ai; return p; } AuthInfo* auth_getinfo(AuthRpc *rpc) { AuthInfo *a; if(auth_rpc(rpc, "authinfo", nil, 0) != ARok) return nil; a = nil; if(convM2AI((uchar*)rpc->arg, rpc->narg, &a) == nil){ werrstr("bad auth info from factotum"); return nil; } return a; } static int dorpc(AuthRpc *rpc, char *verb, char *val, int len, AuthGetkey *getkey) { int ret; for(;;){ if((ret = auth_rpc(rpc, verb, val, len)) != ARneedkey && ret != ARbadkey) return ret; if(getkey == 0) return ARgiveup; /* don't know how */ if((*getkey)(rpc->arg) < 0) return ARgiveup; /* user punted */ } } /* * this just proxies what the factotum tells it to. */ AuthInfo* fauth_proxy(int fd, AuthRpc *rpc, AuthGetkey *getkey, char *params) { char *buf; int m, n, ret; AuthInfo *a; char oerr[ERRMAX]; rerrstr(oerr, sizeof oerr); werrstr("UNKNOWN AUTH ERROR"); if(dorpc(rpc, "start", params, strlen(params), getkey) != ARok){ werrstr("fauth_proxy start: %r"); return nil; } buf = malloc(AuthRpcMax); if(buf == nil) return nil; for(;;){ switch(dorpc(rpc, "read", nil, 0, getkey)){ case ARdone: free(buf); a = auth_getinfo(rpc); errstr(oerr, sizeof oerr); /* no error, restore whatever was there */ return a; case ARok: if(write(fd, rpc->arg, rpc->narg) != rpc->narg){ werrstr("auth_proxy write fd: %r"); goto Error; } break; case ARphase: n = 0; memset(buf, 0, AuthRpcMax); while((ret = dorpc(rpc, "write", buf, n, getkey)) == ARtoosmall){ if(atoi(rpc->arg) > AuthRpcMax) break; m = read(fd, buf+n, atoi(rpc->arg)-n); if(m <= 0){ if(m == 0) werrstr("auth_proxy short read: %s", buf); goto Error; } n += m; } if(ret != ARok){ werrstr("auth_proxy rpc write: %s: %r", buf); goto Error; } break; default: werrstr("auth_proxy rpc: %r"); goto Error; } } Error: free(buf); return nil; } AuthInfo* auth_proxy(int fd, AuthGetkey *getkey, char *fmt, ...) { int afd; char *p; va_list arg; AuthInfo *ai; AuthRpc *rpc; quotefmtinstall(); /* just in case */ va_start(arg, fmt); p = vsmprint(fmt, arg); va_end(arg); afd = open("/mnt/factotum/rpc", ORDWR); if(afd < 0){ werrstr("opening /mnt/factotum/rpc: %r"); free(p); return nil; } rpc = auth_allocrpc(afd); if(rpc == nil){ free(p); return nil; } ai = fauth_proxy(fd, rpc, getkey, p); free(p); auth_freerpc(rpc); close(afd); return ai; } drawterm-20170818/libauth/auth_respond.c000066400000000000000000000026121314554504700201130ustar00rootroot00000000000000#include #include #include #include #include "authlocal.h" enum { ARgiveup = 100, }; static int dorpc(AuthRpc *rpc, char *verb, char *val, int len, AuthGetkey *getkey) { int ret; for(;;){ if((ret = auth_rpc(rpc, verb, val, len)) != ARneedkey && ret != ARbadkey) return ret; if(getkey == 0) return ARgiveup; /* don't know how */ if((*getkey)(rpc->arg) < 0) return ARgiveup; /* user punted */ } } int auth_respond(void *chal, uint nchal, char *user, uint nuser, void *resp, uint nresp, AuthGetkey *getkey, char *fmt, ...) { char *p, *s; va_list arg; int afd; AuthRpc *rpc; Attr *a; if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0) return -1; if((rpc = auth_allocrpc(afd)) == nil){ close(afd); return -1; } quotefmtinstall(); /* just in case */ va_start(arg, fmt); p = vsmprint(fmt, arg); va_end(arg); if(p==nil || dorpc(rpc, "start", p, strlen(p), getkey) != ARok || dorpc(rpc, "write", chal, nchal, getkey) != ARok || dorpc(rpc, "read", nil, 0, getkey) != ARok){ free(p); close(afd); auth_freerpc(rpc); return -1; } free(p); if(rpc->narg < nresp) nresp = rpc->narg; memmove(resp, rpc->arg, nresp); if((a = auth_attr(rpc)) != nil && (s = _strfindattr(a, "user")) != nil && strlen(s) < nuser) strcpy(user, s); else if(nuser > 0) user[0] = '\0'; _freeattr(a); close(afd); auth_freerpc(rpc); return nresp; } drawterm-20170818/libauth/auth_rpc.c000066400000000000000000000040201314554504700172200ustar00rootroot00000000000000#include #include #include #include "authlocal.h" static struct { char *verb; int val; } tab[] = { "ok", ARok, "done", ARdone, "error", ARerror, "needkey", ARneedkey, "badkey", ARbadkey, "phase", ARphase, "toosmall", ARtoosmall, "error", ARerror, }; static int classify(char *buf, uint n, AuthRpc *rpc) { int i, len; for(i=0; i= len && memcmp(buf, tab[i].verb, len) == 0 && (n==len || buf[len]==' ')){ if(n==len){ rpc->narg = 0; rpc->arg = ""; }else{ rpc->narg = n - (len+1); rpc->arg = (char*)buf+len+1; } return tab[i].val; } } werrstr("malformed rpc response: %s", buf); return ARrpcfailure; } AuthRpc* auth_allocrpc(int afd) { AuthRpc *rpc; rpc = mallocz(sizeof(*rpc), 1); if(rpc == nil) return nil; rpc->afd = afd; return rpc; } void auth_freerpc(AuthRpc *rpc) { free(rpc); } uint auth_rpc(AuthRpc *rpc, char *verb, void *a, int na) { int l, n, type; char *f[4]; l = strlen(verb); if(na+l+1 > AuthRpcMax){ werrstr("rpc too big"); return ARtoobig; } memmove(rpc->obuf, verb, l); rpc->obuf[l] = ' '; memmove(rpc->obuf+l+1, a, na); if((n=write(rpc->afd, rpc->obuf, l+1+na)) != l+1+na){ if(n >= 0) werrstr("auth_rpc short write"); return ARrpcfailure; } if((n=read(rpc->afd, rpc->ibuf, AuthRpcMax)) < 0) return ARrpcfailure; rpc->ibuf[n] = '\0'; /* * Set error string for good default behavior. */ switch(type = classify(rpc->ibuf, n, rpc)){ default: werrstr("unknown rpc type %d (bug in auth_rpc.c)", type); break; case ARok: break; case ARrpcfailure: break; case ARerror: if(rpc->narg == 0) werrstr("unspecified rpc error"); else werrstr("%s", rpc->arg); break; case ARneedkey: werrstr("needkey %s", rpc->arg); break; case ARbadkey: if(getfields(rpc->arg, f, nelem(f), 0, "\n") < 2) werrstr("badkey %s", rpc->arg); else werrstr("badkey %s", f[1]); break; case ARphase: werrstr("phase error %s", rpc->arg); break; } return type; } drawterm-20170818/libauth/auth_userpasswd.c000066400000000000000000000021111314554504700206330ustar00rootroot00000000000000#include #include #include #include #include "authlocal.h" /* * compute the proper response. We encrypt the ascii of * challenge number, with trailing binary zero fill. * This process was derived empirically. * this was copied from inet's guard. */ static void netresp(char *key, long chal, char *answer) { uchar buf[8]; memset(buf, 0, 8); sprint((char *)buf, "%lud", chal); if(encrypt(key, buf, 8) < 0) abort(); chal = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+buf[3]; sprint(answer, "%.8lux", chal); } AuthInfo* auth_userpasswd(char *user, char *passwd) { char key[DESKEYLEN], resp[16]; AuthInfo *ai; Chalstate *ch; /* * Probably we should have a factotum protocol * to check a raw password. For now, we use * p9cr, which is simplest to speak. */ if((ch = auth_challenge("user=%q proto=p9cr role=server", user)) == nil) return nil; passtokey(key, passwd); netresp(key, atol(ch->chal), resp); memset(key, 0, sizeof key); ch->resp = resp; ch->nresp = strlen(resp); ai = auth_response(ch); auth_freechal(ch); return ai; } drawterm-20170818/libauth/authlocal.h000066400000000000000000000001271314554504700174000ustar00rootroot00000000000000extern AuthInfo* _fauth_proxy(int fd, AuthRpc *rpc, AuthGetkey *getkey, char *params); drawterm-20170818/libauth/httpauth.c000066400000000000000000000020431314554504700172570ustar00rootroot00000000000000#include #include #include #include /* deprecated. This is the mechanism that put entries in /sys/lib/httpd.rewrite and passwords on the authserver in /sys/lib/httppasswords, which was awkward to administer. Instead, use local .httplogin files, which are implemented in sys/src/cmd/ip/httpd/authorize.c */ int httpauth(char *name, char *password) { int afd; Ticketreq tr; Ticket t; char key[DESKEYLEN]; char buf[512]; afd = authdial(nil, nil); if(afd < 0) return -1; /* send ticket request to AS */ memset(&tr, 0, sizeof(tr)); strcpy(tr.uid, name); tr.type = AuthHttp; convTR2M(&tr, buf); if(write(afd, buf, TICKREQLEN) != TICKREQLEN){ close(afd); return -1; } if(_asrdresp(afd, buf, TICKETLEN) < 0){ close(afd); return -1; } close(afd); /* * use password and try to decrypt the * ticket. If it doesn't work we've got a bad password, * give up. */ passtokey(key, password); convM2T(buf, &t, key); if(t.num != AuthHr || strcmp(t.cuid, tr.uid)) return -1; return 0; } drawterm-20170818/libauthsrv/000077500000000000000000000000001314554504700160065ustar00rootroot00000000000000drawterm-20170818/libauthsrv/Makefile000066400000000000000000000005431314554504700174500ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libauthsrv.a OFILES=\ _asgetticket.$O\ _asrdresp.$O\ convA2M.$O\ convM2A.$O\ convM2PR.$O\ convM2T.$O\ convM2TR.$O\ convPR2M.$O\ convT2M.$O\ convTR2M.$O\ nvcsum.$O\ opasstokey.$O\ passtokey.$O\ default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/libauthsrv/_asgetticket.c000066400000000000000000000004301314554504700206150ustar00rootroot00000000000000#include #include #include static char *pbmsg = "AS protocol botch"; int _asgetticket(int fd, char *trbuf, char *tbuf) { if(write(fd, trbuf, TICKREQLEN) < 0){ close(fd); werrstr(pbmsg); return -1; } return _asrdresp(fd, tbuf, 2*TICKETLEN); } drawterm-20170818/libauthsrv/_asrdresp.c000066400000000000000000000015521314554504700201370ustar00rootroot00000000000000#include #include #include static char *pbmsg = "AS protocol botch"; int _asrdresp(int fd, char *buf, int len) { int n; char error[64]; if(read(fd, buf, 1) != 1){ werrstr(pbmsg); return -1; } n = len; switch(buf[0]){ case AuthOK: if(readn(fd, buf, len) != len){ werrstr(pbmsg); return -1; } break; case AuthErr: if(readn(fd, error, sizeof error) != sizeof error){ werrstr(pbmsg); return -1; } error[sizeof error-1] = '\0'; werrstr("remote: %s", error); return -1; case AuthOKvar: if(readn(fd, error, 5) != 5){ werrstr(pbmsg); return -1; } error[5] = 0; n = atoi(error); if(n <= 0 || n > len){ werrstr(pbmsg); return -1; } memset(buf, 0, len); if(readn(fd, buf, n) != n){ werrstr(pbmsg); return -1; } break; default: werrstr(pbmsg); return -1; } return n; } drawterm-20170818/libauthsrv/authdial.c000066400000000000000000000013071314554504700177460ustar00rootroot00000000000000#include #include #include #include #include int authdial(char *netroot, char *dom) { char server[Ndbvlen]; Ndbtuple *nt; if(dom != nil){ /* look up an auth server in an authentication domain */ nt = csgetval(netroot, "authdom", dom, "auth", server); /* if that didn't work, just try the IP domain */ if(nt == nil) nt = csgetval(netroot, "dom", dom, "auth", server); if(nt == nil){ werrstr("no auth server found for %s", dom); return -1; } ndbfree(nt); return dial(netmkaddr(server, netroot, "ticket"), 0, 0, 0); } else { /* look for one relative to my machine */ return dial(netmkaddr("$auth", netroot, "ticket"), 0, 0, 0); } } drawterm-20170818/libauthsrv/convA2M.c000066400000000000000000000007651314554504700174270ustar00rootroot00000000000000#include #include #include #define CHAR(x) *p++ = f->x #define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2 #define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4 #define LONG(x) VLONG(f->x) #define STRING(x,n) memmove(p, f->x, n); p += n int convA2M(Authenticator *f, char *ap, char *key) { int n; uchar *p; p = (uchar*)ap; CHAR(num); STRING(chal, CHALLEN); LONG(id); n = p - (uchar*)ap; if(key) encrypt(key, ap, n); return n; } drawterm-20170818/libauthsrv/convM2A.c000066400000000000000000000007261314554504700174240ustar00rootroot00000000000000#include #include #include #define CHAR(x) f->x = *p++ #define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2 #define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4 #define LONG(x) VLONG(f->x) #define STRING(x,n) memmove(f->x, p, n); p += n void convM2A(char *ap, Authenticator *f, char *key) { uchar *p; if(key) decrypt(key, ap, AUTHENTLEN); p = (uchar*)ap; CHAR(num); STRING(chal, CHALLEN); LONG(id); USED(p); } drawterm-20170818/libauthsrv/convM2PR.c000066400000000000000000000011421314554504700175560ustar00rootroot00000000000000#include #include #include #define CHAR(x) f->x = *p++ #define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2 #define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4 #define LONG(x) VLONG(f->x) #define STRING(x,n) memmove(f->x, p, n); p += n void convM2PR(char *ap, Passwordreq *f, char *key) { uchar *p; p = (uchar*)ap; if(key) decrypt(key, ap, PASSREQLEN); CHAR(num); STRING(old, ANAMELEN); f->old[ANAMELEN-1] = 0; STRING(new, ANAMELEN); f->new[ANAMELEN-1] = 0; CHAR(changesecret); STRING(secret, SECRETLEN); f->secret[SECRETLEN-1] = 0; USED(p); } drawterm-20170818/libauthsrv/convM2T.c000066400000000000000000000011031314554504700174350ustar00rootroot00000000000000#include #include #include #define CHAR(x) f->x = *p++ #define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2 #define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4 #define LONG(x) VLONG(f->x) #define STRING(x,n) memmove(f->x, p, n); p += n void convM2T(char *ap, Ticket *f, char *key) { uchar *p; if(key) decrypt(key, ap, TICKETLEN); p = (uchar*)ap; CHAR(num); STRING(chal, CHALLEN); STRING(cuid, ANAMELEN); f->cuid[ANAMELEN-1] = 0; STRING(suid, ANAMELEN); f->suid[ANAMELEN-1] = 0; STRING(key, DESKEYLEN); USED(p); } drawterm-20170818/libauthsrv/convM2TR.c000066400000000000000000000011511314554504700175620ustar00rootroot00000000000000#include #include #include #define CHAR(x) f->x = *p++ #define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2 #define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4 #define LONG(x) VLONG(f->x) #define STRING(x,n) memmove(f->x, p, n); p += n void convM2TR(char *ap, Ticketreq *f) { uchar *p; p = (uchar*)ap; CHAR(type); STRING(authid, ANAMELEN); f->authid[ANAMELEN-1] = 0; STRING(authdom, DOMLEN); f->authdom[DOMLEN-1] = 0; STRING(chal, CHALLEN); STRING(hostid, ANAMELEN); f->hostid[ANAMELEN-1] = 0; STRING(uid, ANAMELEN); f->uid[ANAMELEN-1] = 0; USED(p); } drawterm-20170818/libauthsrv/convPR2M.c000066400000000000000000000010631314554504700175600ustar00rootroot00000000000000#include #include #include #define CHAR(x) *p++ = f->x #define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2 #define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4 #define LONG(x) VLONG(f->x) #define STRING(x,n) memmove(p, f->x, n); p += n int convPR2M(Passwordreq *f, char *ap, char *key) { int n; uchar *p; p = (uchar*)ap; CHAR(num); STRING(old, ANAMELEN); STRING(new, ANAMELEN); CHAR(changesecret); STRING(secret, SECRETLEN); n = p - (uchar*)ap; if(key) encrypt(key, ap, n); return n; } drawterm-20170818/libauthsrv/convT2M.c000066400000000000000000000010561314554504700174440ustar00rootroot00000000000000#include #include #include #define CHAR(x) *p++ = f->x #define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2 #define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4 #define LONG(x) VLONG(f->x) #define STRING(x,n) memmove(p, f->x, n); p += n int convT2M(Ticket *f, char *ap, char *key) { int n; uchar *p; p = (uchar*)ap; CHAR(num); STRING(chal, CHALLEN); STRING(cuid, ANAMELEN); STRING(suid, ANAMELEN); STRING(key, DESKEYLEN); n = p - (uchar*)ap; if(key) encrypt(key, ap, n); return n; } drawterm-20170818/libauthsrv/convTR2M.c000066400000000000000000000010621314554504700175630ustar00rootroot00000000000000#include #include #include #define CHAR(x) *p++ = f->x #define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2 #define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4 #define LONG(x) VLONG(f->x) #define STRING(x,n) memmove(p, f->x, n); p += n int convTR2M(Ticketreq *f, char *ap) { int n; uchar *p; p = (uchar*)ap; CHAR(type); STRING(authid, 28); /* BUG */ STRING(authdom, DOMLEN); STRING(chal, CHALLEN); STRING(hostid, 28); /* BUG */ STRING(uid, 28); /* BUG */ n = p - (uchar*)ap; return n; } drawterm-20170818/libauthsrv/nvcsum.c000066400000000000000000000003001314554504700174560ustar00rootroot00000000000000#include #include #include uchar nvcsum(void *vmem, int n) { uchar *mem, sum; int i; sum = 9; mem = vmem; for(i = 0; i < n; i++) sum += mem[i]; return sum; } drawterm-20170818/libauthsrv/opasstokey.c000066400000000000000000000007001314554504700203500ustar00rootroot00000000000000#include #include #include int opasstokey(char *key, char *p) { uchar t[10]; int c, n; n = strlen(p); memset(t, ' ', sizeof t); if(n < 5) return 0; if(n > 10) n = 10; strncpy((char*)t, p, n); if(n >= 9){ c = p[8] & 0xf; if(n == 10) c += p[9] << 4; for(n = 0; n < 8; n++) if(c & (1 << n)) t[n] -= ' '; } for(n = 0; n < 7; n++) key[n] = (t[n] >> n) + (t[n+1] << (8 - (n+1))); return 1; } drawterm-20170818/libauthsrv/passtokey.c000066400000000000000000000010051314554504700201700ustar00rootroot00000000000000#include #include #include int passtokey(char *key, char *p) { uchar buf[ANAMELEN], *t; int i, n; n = strlen(p); if(n >= ANAMELEN) n = ANAMELEN-1; memset(buf, ' ', 8); t = buf; strncpy((char*)t, p, n); t[n] = 0; memset(key, 0, DESKEYLEN); for(;;){ for(i = 0; i < DESKEYLEN; i++) key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1))); if(n <= 8) return 1; n -= 8; t += 8; if(n < 8){ t -= 8 - n; n = 8; } encrypt(key, t, 8); } return 1; /* not reached */ } drawterm-20170818/libauthsrv/readnvram.c000066400000000000000000000203761314554504700201410ustar00rootroot00000000000000#include #include #include static long finddosfile(int, char*); static int check(void *x, int len, uchar sum, char *msg) { if(nvcsum(x, len) == sum) return 0; memset(x, 0, len); fprint(2, "%s\n", msg); return 1; } /* * get key info out of nvram. since there isn't room in the PC's nvram use * a disk partition there. */ static struct { char *cputype; char *file; int off; int len; } nvtab[] = { "sparc", "#r/nvram", 1024+850, sizeof(Nvrsafe), "pc", "#S/sdC0/nvram", 0, sizeof(Nvrsafe), "pc", "#S/sdC0/9fat", -1, sizeof(Nvrsafe), "pc", "#S/sd00/nvram", 0, sizeof(Nvrsafe), "pc", "#S/sd00/9fat", -1, sizeof(Nvrsafe), "pc", "#S/sd01/nvram", 0, sizeof(Nvrsafe), "pc", "#S/sd01/9fat", -1, sizeof(Nvrsafe), "pc", "#f/fd0disk", -1, 512, /* 512: #f requires whole sector reads */ "pc", "#f/fd1disk", -1, 512, "mips", "#r/nvram", 1024+900, sizeof(Nvrsafe), "power", "#F/flash/flash0", 0x300000, sizeof(Nvrsafe), "power", "#r/nvram", 4352, sizeof(Nvrsafe), /* OK for MTX-604e */ "debug", "/tmp/nvram", 0, sizeof(Nvrsafe), }; static char* readcons(char *prompt, char *def, int raw, char *buf, int nbuf) { int fdin, fdout, ctl, n, m; char line[10]; fdin = open("/dev/cons", OREAD); if(fdin < 0) fdin = 0; fdout = open("/dev/cons", OWRITE); if(fdout < 0) fdout = 1; if(def != nil) fprint(fdout, "%s[%s]: ", prompt, def); else fprint(fdout, "%s: ", prompt); if(raw){ ctl = open("/dev/consctl", OWRITE); if(ctl >= 0) write(ctl, "rawon", 5); } else ctl = -1; m = 0; for(;;){ n = read(fdin, line, 1); if(n == 0){ close(ctl); werrstr("readcons: EOF"); return nil; } if(n < 0){ close(ctl); werrstr("can't read cons"); return nil; } if(line[0] == 0x7f) exits(0); if(n == 0 || line[0] == '\n' || line[0] == '\r'){ if(raw){ write(ctl, "rawoff", 6); write(fdout, "\n", 1); close(ctl); } buf[m] = '\0'; if(buf[0]=='\0' && def) strcpy(buf, def); return buf; } if(line[0] == '\b'){ if(m > 0) m--; }else if(line[0] == 0x15){ /* ^U: line kill */ m = 0; if(def != nil) fprint(fdout, "%s[%s]: ", prompt, def); else fprint(fdout, "%s: ", prompt); }else{ if(m >= nbuf-1){ fprint(fdout, "line too long\n"); m = 0; if(def != nil) fprint(fdout, "%s[%s]: ", prompt, def); else fprint(fdout, "%s: ", prompt); }else buf[m++] = line[0]; } } return buf; /* how does this happen */ } /* * get key info out of nvram. since there isn't room in the PC's nvram use * a disk partition there. */ int readnvram(Nvrsafe *safep, int flag) { char buf[1024], in[128], *cputype, *nvrfile, *nvrlen, *nvroff, *v[2]; int fd, err, i, safeoff, safelen; Nvrsafe *safe; err = 0; memset(safep, 0, sizeof(*safep)); nvrfile = getenv("nvram"); cputype = getenv("cputype"); if(cputype == nil) cputype = "mips"; if(strcmp(cputype, "386")==0 || strcmp(cputype, "alpha")==0) cputype = "pc"; safe = (Nvrsafe*)buf; fd = -1; safeoff = -1; safelen = -1; if(nvrfile != nil){ /* accept device and device!file */ i = gettokens(nvrfile, v, nelem(v), "!"); fd = open(v[0], ORDWR); safelen = sizeof(Nvrsafe); if(strstr(v[0], "/9fat") == nil) safeoff = 0; nvrlen = getenv("nvrlen"); if(nvrlen != nil) safelen = atoi(nvrlen); nvroff = getenv("nvroff"); if(nvroff != nil){ if(strcmp(nvroff, "dos") == 0) safeoff = -1; else safeoff = atoi(nvroff); } if(safeoff < 0 && fd >= 0){ safelen = 512; safeoff = finddosfile(fd, i == 2 ? v[1] : "plan9.nvr"); if(safeoff < 0){ close(fd); fd = -1; } } free(nvrfile); if(nvrlen != nil) free(nvrlen); if(nvroff != nil) free(nvroff); }else{ for(i=0; imachkey, DESKEYLEN, safe->machsum, "bad nvram key"); // err |= check(safe->config, CONFIGLEN, safe->configsum, "bad secstore key"); err |= check(safe->authid, ANAMELEN, safe->authidsum, "bad authentication id"); err |= check(safe->authdom, DOMLEN, safe->authdomsum, "bad authentication domain"); } if((flag&NVwrite) || (err && (flag&NVwriteonerr))){ readcons("authid", nil, 0, safe->authid, sizeof(safe->authid)); readcons("authdom", nil, 0, safe->authdom, sizeof(safe->authdom)); readcons("secstore key", nil, 1, safe->config, sizeof(safe->config)); for(;;){ if(readcons("password", nil, 1, in, sizeof in) == nil) goto Out; if(passtokey(safe->machkey, in)) break; } safe->machsum = nvcsum(safe->machkey, DESKEYLEN); safe->configsum = nvcsum(safe->config, CONFIGLEN); safe->authidsum = nvcsum(safe->authid, sizeof(safe->authid)); safe->authdomsum = nvcsum(safe->authdom, sizeof(safe->authdom)); *(Nvrsafe*)buf = *safe; if(seek(fd, safeoff, 0) < 0 || write(fd, buf, safelen) != safelen){ fprint(2, "can't write key to nvram: %r\n"); err = 1; }else err = 0; } Out: close(fd); return err ? -1 : 0; } typedef struct Dosboot Dosboot; struct Dosboot{ uchar magic[3]; /* really an xx86 JMP instruction */ uchar version[8]; uchar sectsize[2]; uchar clustsize; uchar nresrv[2]; uchar nfats; uchar rootsize[2]; uchar volsize[2]; uchar mediadesc; uchar fatsize[2]; uchar trksize[2]; uchar nheads[2]; uchar nhidden[4]; uchar bigvolsize[4]; uchar driveno; uchar reserved0; uchar bootsig; uchar volid[4]; uchar label[11]; uchar type[8]; }; #define GETSHORT(p) (((p)[1]<<8) | (p)[0]) #define GETLONG(p) ((GETSHORT((p)+2) << 16) | GETSHORT((p))) typedef struct Dosdir Dosdir; struct Dosdir { char name[8]; char ext[3]; uchar attr; uchar reserved[10]; uchar time[2]; uchar date[2]; uchar start[2]; uchar length[4]; }; static char* dosparse(char *from, char *to, int len) { char c; memset(to, ' ', len); if(from == 0) return 0; while(len-- > 0){ c = *from++; if(c == '.') return from; if(c == 0) break; if(c >= 'a' && c <= 'z') *to++ = c + 'A' - 'a'; else *to++ = c; } return 0; } /* * return offset of first file block * * This is a very simplistic dos file system. It only * works on floppies, only looks in the root, and only * returns a pointer to the first block of a file. * * This exists for cpu servers that have no hard disk * or nvram to store the key on. * * Please don't make this any smarter: it stays resident * and I'ld prefer not to waste the space on something that * runs only at boottime -- presotto. */ static long finddosfile(int fd, char *file) { uchar secbuf[512]; char name[8]; char ext[3]; Dosboot *b; Dosdir *root, *dp; int nroot, sectsize, rootoff, rootsects, n; /* dos'ize file name */ file = dosparse(file, name, 8); dosparse(file, ext, 3); /* read boot block, check for sanity */ b = (Dosboot*)secbuf; if(read(fd, secbuf, sizeof(secbuf)) != sizeof(secbuf)) return -1; if(b->magic[0] != 0xEB || b->magic[1] != 0x3C || b->magic[2] != 0x90) return -1; sectsize = GETSHORT(b->sectsize); if(sectsize != 512) return -1; rootoff = (GETSHORT(b->nresrv) + b->nfats*GETSHORT(b->fatsize)) * sectsize; if(seek(fd, rootoff, 0) < 0) return -1; nroot = GETSHORT(b->rootsize); rootsects = (nroot*sizeof(Dosdir)+sectsize-1)/sectsize; if(rootsects <= 0 || rootsects > 64) return -1; /* * read root. it is contiguous to make stuff like * this easier */ root = malloc(rootsects*sectsize); if(read(fd, root, rootsects*sectsize) != rootsects*sectsize) return -1; n = -1; for(dp = root; dp < &root[nroot]; dp++) if(memcmp(name, dp->name, 8) == 0 && memcmp(ext, dp->ext, 3) == 0){ n = GETSHORT(dp->start); break; } free(root); if(n < 0) return -1; /* * dp->start is in cluster units, not sectors. The first * cluster is cluster 2 which starts immediately after the * root directory */ return rootoff + rootsects*sectsize + (n-2)*sectsize*b->clustsize; } drawterm-20170818/libc/000077500000000000000000000000001314554504700145345ustar00rootroot00000000000000drawterm-20170818/libc/Makefile000066400000000000000000000022451314554504700161770ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libc.a OFILES=\ charstod.$O\ cleanname.$O\ convD2M.$O\ convM2D.$O\ convM2S.$O\ convS2M.$O\ crypt.$O\ dial.$O\ dirfstat.$O\ dirfwstat.$O\ dirmodefmt.$O\ dirstat.$O\ dirwstat.$O\ dofmt.$O\ dorfmt.$O\ encodefmt.$O\ fcallfmt.$O\ fltfmt.$O\ fmt.$O\ fmtfd.$O\ fmtfdflush.$O\ fmtlock.$O\ fmtprint.$O\ fmtquote.$O\ fmtrune.$O\ fmtstr.$O\ fmtvprint.$O\ fprint.$O\ getfields.$O\ getpid.$O\ lock.$O\ mallocz.$O\ nan64.$O\ netmkaddr.$O\ nsec.$O\ pow10.$O\ pushssl.$O\ pushtls.$O\ read9pmsg.$O\ readn.$O\ rune.$O\ runefmtstr.$O\ runeseprint.$O\ runesmprint.$O\ runesnprint.$O\ runesprint.$O\ runestrchr.$O\ runestrlen.$O\ runestrstr.$O\ runetype.$O\ runevseprint.$O\ runevsmprint.$O\ runevsnprint.$O\ seprint.$O\ smprint.$O\ snprint.$O\ sprint.$O\ strecpy.$O\ strtod.$O\ strtoll.$O\ sysfatal.$O\ time.$O\ tokenize.$O\ truerand.$O\ u16.$O\ u32.$O\ u64.$O\ utfecpy.$O\ utflen.$O\ utfnlen.$O\ utfrrune.$O\ utfrune.$O\ utfutf.$O\ vfprint.$O\ vseprint.$O\ vsmprint.$O\ vsnprint.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/libc/charstod.c000066400000000000000000000022631314554504700165120ustar00rootroot00000000000000#include #include #include "fmtdef.h" /* * Reads a floating-point number by interpreting successive characters * returned by (*f)(vp). The last call it makes to f terminates the * scan, so is not a character in the number. It may therefore be * necessary to back up the input stream up one byte after calling charstod. */ double fmtcharstod(int(*f)(void*), void *vp) { double num, dem; int neg, eneg, dig, exp, c; num = 0; neg = 0; dig = 0; exp = 0; eneg = 0; c = (*f)(vp); while(c == ' ' || c == '\t') c = (*f)(vp); if(c == '-' || c == '+'){ if(c == '-') neg = 1; c = (*f)(vp); } while(c >= '0' && c <= '9'){ num = num*10 + c-'0'; c = (*f)(vp); } if(c == '.') c = (*f)(vp); while(c >= '0' && c <= '9'){ num = num*10 + c-'0'; dig++; c = (*f)(vp); } if(c == 'e' || c == 'E'){ c = (*f)(vp); if(c == '-' || c == '+'){ if(c == '-'){ dig = -dig; eneg = 1; } c = (*f)(vp); } while(c >= '0' && c <= '9'){ exp = exp*10 + c-'0'; c = (*f)(vp); } } exp -= dig; if(exp < 0){ exp = -exp; eneg = !eneg; } dem = __fmtpow10(exp); if(eneg) num /= dem; else num *= dem; if(neg) return -num; return num; } drawterm-20170818/libc/cleanname.c000066400000000000000000000022571314554504700166310ustar00rootroot00000000000000#include #include /* * In place, rewrite name to compress multiple /, eliminate ., and process .. */ #define SEP(x) ((x)=='/' || (x) == 0) char* cleanname(char *name) { char *p, *q, *dotdot; int rooted; rooted = name[0] == '/'; /* * invariants: * p points at beginning of path element we're considering. * q points just past the last path element we wrote (no slash). * dotdot points just past the point where .. cannot backtrack * any further (no slash). */ p = q = dotdot = name+rooted; while(*p) { if(p[0] == '/') /* null element */ p++; else if(p[0] == '.' && SEP(p[1])) p += 1; /* don't count the separator in case it is nul */ else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) { p += 2; if(q > dotdot) { /* can backtrack */ while(--q > dotdot && *q != '/') ; } else if(!rooted) { /* /.. is / but ./../ is .. */ if(q != name) *q++ = '/'; *q++ = '.'; *q++ = '.'; dotdot = q; } } else { /* real path element */ if(q != name+rooted) *q++ = '/'; while((*q = *p) != '/' && *q != 0) p++, q++; } } if(q == name) /* empty string is really ``.'' */ *q++ = '.'; *q = '\0'; return name; } drawterm-20170818/libc/convD2M.c000066400000000000000000000025661314554504700161610ustar00rootroot00000000000000#include #include #include uint sizeD2M(Dir *d) { char *sv[4]; int i, ns; sv[0] = d->name; sv[1] = d->uid; sv[2] = d->gid; sv[3] = d->muid; ns = 0; for(i = 0; i < 4; i++) if(sv[i]) ns += strlen(sv[i]); return STATFIXLEN + ns; } uint convD2M(Dir *d, uchar *buf, uint nbuf) { uchar *p, *ebuf; char *sv[4]; int i, ns, nsv[4], ss; if(nbuf < BIT16SZ) return 0; p = buf; ebuf = buf + nbuf; sv[0] = d->name; sv[1] = d->uid; sv[2] = d->gid; sv[3] = d->muid; ns = 0; for(i = 0; i < 4; i++){ if(sv[i]) nsv[i] = strlen(sv[i]); else nsv[i] = 0; ns += nsv[i]; } ss = STATFIXLEN + ns; /* set size befor erroring, so user can know how much is needed */ /* note that length excludes count field itself */ PBIT16(p, ss-BIT16SZ); p += BIT16SZ; if(ss > nbuf) return BIT16SZ; PBIT16(p, d->type); p += BIT16SZ; PBIT32(p, d->dev); p += BIT32SZ; PBIT8(p, d->qid.type); p += BIT8SZ; PBIT32(p, d->qid.vers); p += BIT32SZ; PBIT64(p, d->qid.path); p += BIT64SZ; PBIT32(p, d->mode); p += BIT32SZ; PBIT32(p, d->atime); p += BIT32SZ; PBIT32(p, d->mtime); p += BIT32SZ; PBIT64(p, d->length); p += BIT64SZ; for(i = 0; i < 4; i++){ ns = nsv[i]; if(p + ns + BIT16SZ > ebuf) return 0; PBIT16(p, ns); p += BIT16SZ; if(ns) memmove(p, sv[i], ns); p += ns; } if(ss != p - buf) return 0; return p - buf; } drawterm-20170818/libc/convM2D.c000066400000000000000000000026131314554504700161520ustar00rootroot00000000000000#include #include #include int statcheck(uchar *buf, uint nbuf) { uchar *ebuf; int i; ebuf = buf + nbuf; if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf)) return -1; buf += STATFIXLEN - 4 * BIT16SZ; for(i = 0; i < 4; i++){ if(buf + BIT16SZ > ebuf) return -1; buf += BIT16SZ + GBIT16(buf); } if(buf != ebuf) return -1; return 0; } static char nullstring[] = ""; uint convM2D(uchar *buf, uint nbuf, Dir *d, char *strs) { uchar *p, *ebuf; char *sv[4]; int i, ns; if(nbuf < STATFIXLEN) return 0; p = buf; ebuf = buf + nbuf; p += BIT16SZ; /* ignore size */ d->type = GBIT16(p); p += BIT16SZ; d->dev = GBIT32(p); p += BIT32SZ; d->qid.type = GBIT8(p); p += BIT8SZ; d->qid.vers = GBIT32(p); p += BIT32SZ; d->qid.path = GBIT64(p); p += BIT64SZ; d->mode = GBIT32(p); p += BIT32SZ; d->atime = GBIT32(p); p += BIT32SZ; d->mtime = GBIT32(p); p += BIT32SZ; d->length = GBIT64(p); p += BIT64SZ; for(i = 0; i < 4; i++){ if(p + BIT16SZ > ebuf) return 0; ns = GBIT16(p); p += BIT16SZ; if(p + ns > ebuf) return 0; if(strs){ sv[i] = strs; memmove(strs, p, ns); strs += ns; *strs++ = '\0'; } p += ns; } if(strs){ d->name = sv[0]; d->uid = sv[1]; d->gid = sv[2]; d->muid = sv[3]; }else{ d->name = nullstring; d->uid = nullstring; d->gid = nullstring; d->muid = nullstring; } return p - buf; } drawterm-20170818/libc/convM2S.c000066400000000000000000000115511314554504700161720ustar00rootroot00000000000000#include #include #include static uchar* gstring(uchar *p, uchar *ep, char **s) { uint n; if(p+BIT16SZ > ep) return nil; n = GBIT16(p); p += BIT16SZ - 1; if(p+n+1 > ep) return nil; /* move it down, on top of count, to make room for '\0' */ memmove(p, p + 1, n); p[n] = '\0'; *s = (char*)p; p += n+1; return p; } static uchar* gqid(uchar *p, uchar *ep, Qid *q) { if(p+QIDSZ > ep) return nil; q->type = GBIT8(p); p += BIT8SZ; q->vers = GBIT32(p); p += BIT32SZ; q->path = GBIT64(p); p += BIT64SZ; return p; } /* * no syntactic checks. * three causes for error: * 1. message size field is incorrect * 2. input buffer too short for its own data (counts too long, etc.) * 3. too many names or qids * gqid() and gstring() return nil if they would reach beyond buffer. * main switch statement checks range and also can fall through * to test at end of routine. */ uint convM2S(uchar *ap, uint nap, Fcall *f) { uchar *p, *ep; uint i, size; p = ap; ep = p + nap; if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep) return 0; size = GBIT32(p); p += BIT32SZ; if(size < BIT32SZ+BIT8SZ+BIT16SZ) return 0; f->type = GBIT8(p); p += BIT8SZ; f->tag = GBIT16(p); p += BIT16SZ; switch(f->type) { default: return 0; case Tversion: if(p+BIT32SZ > ep) return 0; f->msize = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->version); break; case Tflush: if(p+BIT16SZ > ep) return 0; f->oldtag = GBIT16(p); p += BIT16SZ; break; case Tauth: if(p+BIT32SZ > ep) return 0; f->afid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->uname); if(p == nil) break; p = gstring(p, ep, &f->aname); if(p == nil) break; break; case Tattach: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; if(p+BIT32SZ > ep) return 0; f->afid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->uname); if(p == nil) break; p = gstring(p, ep, &f->aname); if(p == nil) break; break; case Twalk: if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->newfid = GBIT32(p); p += BIT32SZ; f->nwname = GBIT16(p); p += BIT16SZ; if(f->nwname > MAXWELEM) return 0; for(i=0; inwname; i++){ p = gstring(p, ep, &f->wname[i]); if(p == nil) break; } break; case Topen: if(p+BIT32SZ+BIT8SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->mode = GBIT8(p); p += BIT8SZ; break; case Tcreate: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->name); if(p == nil) break; if(p+BIT32SZ+BIT8SZ > ep) return 0; f->perm = GBIT32(p); p += BIT32SZ; f->mode = GBIT8(p); p += BIT8SZ; break; case Tread: if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->offset = GBIT64(p); p += BIT64SZ; f->count = GBIT32(p); p += BIT32SZ; break; case Twrite: if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->offset = GBIT64(p); p += BIT64SZ; f->count = GBIT32(p); p += BIT32SZ; if(p+f->count > ep) return 0; f->data = (char*)p; p += f->count; break; case Tclunk: case Tremove: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; break; case Tstat: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; break; case Twstat: if(p+BIT32SZ+BIT16SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->nstat = GBIT16(p); p += BIT16SZ; if(p+f->nstat > ep) return 0; f->stat = p; p += f->nstat; break; /* */ case Rversion: if(p+BIT32SZ > ep) return 0; f->msize = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->version); break; case Rerror: p = gstring(p, ep, &f->ename); break; case Rflush: break; case Rauth: p = gqid(p, ep, &f->aqid); if(p == nil) break; break; case Rattach: p = gqid(p, ep, &f->qid); if(p == nil) break; break; case Rwalk: if(p+BIT16SZ > ep) return 0; f->nwqid = GBIT16(p); p += BIT16SZ; if(f->nwqid > MAXWELEM) return 0; for(i=0; inwqid; i++){ p = gqid(p, ep, &f->wqid[i]); if(p == nil) break; } break; case Ropen: case Rcreate: p = gqid(p, ep, &f->qid); if(p == nil) break; if(p+BIT32SZ > ep) return 0; f->iounit = GBIT32(p); p += BIT32SZ; break; case Rread: if(p+BIT32SZ > ep) return 0; f->count = GBIT32(p); p += BIT32SZ; if(p+f->count > ep) return 0; f->data = (char*)p; p += f->count; break; case Rwrite: if(p+BIT32SZ > ep) return 0; f->count = GBIT32(p); p += BIT32SZ; break; case Rclunk: case Rremove: break; case Rstat: if(p+BIT16SZ > ep) return 0; f->nstat = GBIT16(p); p += BIT16SZ; if(p+f->nstat > ep) return 0; f->stat = p; p += f->nstat; break; case Rwstat: break; } if(p==nil || p>ep) return 0; if(ap+size == p) return size; return 0; } drawterm-20170818/libc/convS2M.c000066400000000000000000000116261314554504700161750ustar00rootroot00000000000000#include #include #include static uchar* pstring(uchar *p, char *s) { uint n; if(s == nil){ PBIT16(p, 0); p += BIT16SZ; return p; } n = strlen(s); PBIT16(p, n); p += BIT16SZ; memmove(p, s, n); p += n; return p; } static uchar* pqid(uchar *p, Qid *q) { PBIT8(p, q->type); p += BIT8SZ; PBIT32(p, q->vers); p += BIT32SZ; PBIT64(p, q->path); p += BIT64SZ; return p; } static uint stringsz(char *s) { if(s == nil) return BIT16SZ; return BIT16SZ+strlen(s); } uint sizeS2M(Fcall *f) { uint n; int i; n = 0; n += BIT32SZ; /* size */ n += BIT8SZ; /* type */ n += BIT16SZ; /* tag */ switch(f->type) { default: return 0; case Tversion: n += BIT32SZ; n += stringsz(f->version); break; case Tflush: n += BIT16SZ; break; case Tauth: n += BIT32SZ; n += stringsz(f->uname); n += stringsz(f->aname); break; case Tattach: n += BIT32SZ; n += BIT32SZ; n += stringsz(f->uname); n += stringsz(f->aname); break; case Twalk: n += BIT32SZ; n += BIT32SZ; n += BIT16SZ; for(i=0; inwname; i++) n += stringsz(f->wname[i]); break; case Topen: n += BIT32SZ; n += BIT8SZ; break; case Tcreate: n += BIT32SZ; n += stringsz(f->name); n += BIT32SZ; n += BIT8SZ; break; case Tread: n += BIT32SZ; n += BIT64SZ; n += BIT32SZ; break; case Twrite: n += BIT32SZ; n += BIT64SZ; n += BIT32SZ; n += f->count; break; case Tclunk: case Tremove: n += BIT32SZ; break; case Tstat: n += BIT32SZ; break; case Twstat: n += BIT32SZ; n += BIT16SZ; n += f->nstat; break; /* */ case Rversion: n += BIT32SZ; n += stringsz(f->version); break; case Rerror: n += stringsz(f->ename); break; case Rflush: break; case Rauth: n += QIDSZ; break; case Rattach: n += QIDSZ; break; case Rwalk: n += BIT16SZ; n += f->nwqid*QIDSZ; break; case Ropen: case Rcreate: n += QIDSZ; n += BIT32SZ; break; case Rread: n += BIT32SZ; n += f->count; break; case Rwrite: n += BIT32SZ; break; case Rclunk: break; case Rremove: break; case Rstat: n += BIT16SZ; n += f->nstat; break; case Rwstat: break; } return n; } uint convS2M(Fcall *f, uchar *ap, uint nap) { uchar *p; uint i, size; size = sizeS2M(f); if(size == 0) return 0; if(size > nap) return 0; p = (uchar*)ap; PBIT32(p, size); p += BIT32SZ; PBIT8(p, f->type); p += BIT8SZ; PBIT16(p, f->tag); p += BIT16SZ; switch(f->type) { default: return 0; case Tversion: PBIT32(p, f->msize); p += BIT32SZ; p = pstring(p, f->version); break; case Tflush: PBIT16(p, f->oldtag); p += BIT16SZ; break; case Tauth: PBIT32(p, f->afid); p += BIT32SZ; p = pstring(p, f->uname); p = pstring(p, f->aname); break; case Tattach: PBIT32(p, f->fid); p += BIT32SZ; PBIT32(p, f->afid); p += BIT32SZ; p = pstring(p, f->uname); p = pstring(p, f->aname); break; case Twalk: PBIT32(p, f->fid); p += BIT32SZ; PBIT32(p, f->newfid); p += BIT32SZ; PBIT16(p, f->nwname); p += BIT16SZ; if(f->nwname > MAXWELEM) return 0; for(i=0; inwname; i++) p = pstring(p, f->wname[i]); break; case Topen: PBIT32(p, f->fid); p += BIT32SZ; PBIT8(p, f->mode); p += BIT8SZ; break; case Tcreate: PBIT32(p, f->fid); p += BIT32SZ; p = pstring(p, f->name); PBIT32(p, f->perm); p += BIT32SZ; PBIT8(p, f->mode); p += BIT8SZ; break; case Tread: PBIT32(p, f->fid); p += BIT32SZ; PBIT64(p, f->offset); p += BIT64SZ; PBIT32(p, f->count); p += BIT32SZ; break; case Twrite: PBIT32(p, f->fid); p += BIT32SZ; PBIT64(p, f->offset); p += BIT64SZ; PBIT32(p, f->count); p += BIT32SZ; memmove(p, f->data, f->count); p += f->count; break; case Tclunk: case Tremove: PBIT32(p, f->fid); p += BIT32SZ; break; case Tstat: PBIT32(p, f->fid); p += BIT32SZ; break; case Twstat: PBIT32(p, f->fid); p += BIT32SZ; PBIT16(p, f->nstat); p += BIT16SZ; memmove(p, f->stat, f->nstat); p += f->nstat; break; /* */ case Rversion: PBIT32(p, f->msize); p += BIT32SZ; p = pstring(p, f->version); break; case Rerror: p = pstring(p, f->ename); break; case Rflush: break; case Rauth: p = pqid(p, &f->aqid); break; case Rattach: p = pqid(p, &f->qid); break; case Rwalk: PBIT16(p, f->nwqid); p += BIT16SZ; if(f->nwqid > MAXWELEM) return 0; for(i=0; inwqid; i++) p = pqid(p, &f->wqid[i]); break; case Ropen: case Rcreate: p = pqid(p, &f->qid); PBIT32(p, f->iounit); p += BIT32SZ; break; case Rread: PBIT32(p, f->count); p += BIT32SZ; memmove(p, f->data, f->count); p += f->count; break; case Rwrite: PBIT32(p, f->count); p += BIT32SZ; break; case Rclunk: break; case Rremove: break; case Rstat: PBIT16(p, f->nstat); p += BIT16SZ; memmove(p, f->stat, f->nstat); p += f->nstat; break; case Rwstat: break; } if(size != p-ap) return 0; return size; } drawterm-20170818/libc/crypt.c000066400000000000000000000020251314554504700160400ustar00rootroot00000000000000/* * Data Encryption Standard * D.P.Mitchell 83/06/08. * * block_cipher(key, block, decrypting) * * these routines use the non-standard 7 byte format * for DES keys. */ #include #include #include #include /* * destructively encrypt the buffer, which * must be at least 8 characters long. */ int encrypt(void *key, void *vbuf, int n) { ulong ekey[32]; uchar *buf; int i, r; if(n < 8) return 0; key_setup(key, ekey); buf = vbuf; n--; r = n % 7; n /= 7; for(i = 0; i < n; i++){ block_cipher(ekey, buf, 0); buf += 7; } if(r) block_cipher(ekey, buf - 7 + r, 0); return 1; } /* * destructively decrypt the buffer, which * must be at least 8 characters long. */ int decrypt(void *key, void *vbuf, int n) { ulong ekey[128]; uchar *buf; int i, r; if(n < 8) return 0; key_setup(key, ekey); buf = vbuf; n--; r = n % 7; n /= 7; buf += n * 7; if(r) block_cipher(ekey, buf - 7 + r, 1); for(i = 0; i < n; i++){ buf -= 7; block_cipher(ekey, buf, 1); } return 1; } drawterm-20170818/libc/dial.c000066400000000000000000000071671314554504700156240ustar00rootroot00000000000000#include #include typedef struct DS DS; static int call(char*, char*, DS*); static int csdial(DS*); static void _dial_string_parse(char*, DS*); enum { Maxstring = 128, Maxpath = 256, }; struct DS { /* dist string */ char buf[Maxstring]; char *netdir; char *proto; char *rem; /* other args */ char *local; char *dir; int *cfdp; }; /* * the dialstring is of the form '[/net/]proto!dest' */ int dial(char *dest, char *local, char *dir, int *cfdp) { DS ds; int rv; char err[ERRMAX], alterr[ERRMAX]; ds.local = local; ds.dir = dir; ds.cfdp = cfdp; _dial_string_parse(dest, &ds); if(ds.netdir) return csdial(&ds); ds.netdir = "/net"; rv = csdial(&ds); if(rv >= 0) return rv; err[0] = '\0'; errstr(err, sizeof err); if(strstr(err, "refused") != 0){ werrstr("%s", err); return rv; } ds.netdir = "/net.alt"; rv = csdial(&ds); if(rv >= 0) return rv; alterr[0] = 0; errstr(alterr, sizeof alterr); if(strstr(alterr, "translate") || strstr(alterr, "does not exist")) werrstr("%s", err); else werrstr("%s", alterr); return rv; } static int csdial(DS *ds) { int n, fd, rv; char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX]; /* * open connection server */ snprint(buf, sizeof(buf), "%s/cs", ds->netdir); fd = open(buf, ORDWR); if(fd < 0){ /* no connection server, don't translate */ snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto); return call(clone, ds->rem, ds); } /* * ask connection server to translate */ snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem); if(write(fd, buf, strlen(buf)) < 0){ close(fd); return -1; } /* * loop through each address from the connection server till * we get one that works. */ *besterr = 0; rv = -1; seek(fd, 0, 0); strcpy(err, "cs gave empty translation list"); while((n = read(fd, buf, sizeof(buf) - 1)) > 0){ buf[n] = 0; p = strchr(buf, ' '); if(p == 0) continue; *p++ = 0; rv = call(buf, p, ds); if(rv >= 0) break; err[0] = '\0'; errstr(err, sizeof err); if(strstr(err, "does not exist") == 0) strcpy(besterr, err); } close(fd); if(rv < 0 && *besterr) werrstr("%s", besterr); else werrstr("%s", err); return rv; } static int call(char *clone, char *dest, DS *ds) { int fd, cfd, n; char name[Maxpath], data[Maxpath], *p; cfd = open(clone, ORDWR); if(cfd < 0) return -1; /* get directory name */ n = read(cfd, name, sizeof(name)-1); if(n < 0){ close(cfd); return -1; } name[n] = 0; for(p = name; *p == ' '; p++) ; snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0)); p = strrchr(clone, '/'); *p = 0; if(ds->dir) snprint(ds->dir, NETPATHLEN, "%s/%s", clone, name); snprint(data, sizeof(data), "%s/%s/data", clone, name); /* connect */ if(ds->local) snprint(name, sizeof(name), "connect %s %s", dest, ds->local); else snprint(name, sizeof(name), "connect %s", dest); if(write(cfd, name, strlen(name)) < 0){ close(cfd); return -1; } /* open data connection */ fd = open(data, ORDWR); if(fd < 0){ print("open %s: %r\n", data); close(cfd); return -1; } if(ds->cfdp) *ds->cfdp = cfd; else close(cfd); return fd; } /* * parse a dial string */ static void _dial_string_parse(char *str, DS *ds) { char *p, *p2; strncpy(ds->buf, str, Maxstring); ds->buf[Maxstring-1] = 0; p = strchr(ds->buf, '!'); if(p == 0) { ds->netdir = 0; ds->proto = "net"; ds->rem = ds->buf; } else { if(*ds->buf != '/' && *ds->buf != '#'){ ds->netdir = 0; ds->proto = ds->buf; } else { for(p2 = p; *p2 != '/'; p2--) ; *p2++ = 0; ds->netdir = ds->buf; ds->proto = p2; } *p = 0; ds->rem = p + 1; } } drawterm-20170818/libc/dirfstat.c000066400000000000000000000012441314554504700165210ustar00rootroot00000000000000#include #include #include enum { DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */ }; Dir* dirfstat(int fd) { Dir *d; uchar *buf; int n, nd, i; nd = DIRSIZE; for(i=0; i<2; i++){ /* should work by the second try */ d = malloc(sizeof(Dir) + BIT16SZ + nd); if(d == nil) return nil; buf = (uchar*)&d[1]; n = fstat(fd, buf, BIT16SZ+nd); if(n < BIT16SZ){ free(d); return nil; } nd = GBIT16(buf); /* upper bound on size of Dir + strings */ if(nd <= n){ convM2D(buf, n, d, (char*)&d[1]); return d; } /* else sizeof(Dir)+BIT16SZ+nd is plenty */ free(d); } return nil; } drawterm-20170818/libc/dirfwstat.c000066400000000000000000000003621314554504700167100ustar00rootroot00000000000000#include #include #include int dirfwstat(int fd, Dir *d) { uchar *buf; int r; r = sizeD2M(d); buf = malloc(r); if(buf == nil) return -1; convD2M(d, buf, r); r = fwstat(fd, buf, r); free(buf); return r; } drawterm-20170818/libc/dirmodefmt.c000066400000000000000000000011051314554504700170270ustar00rootroot00000000000000#include #include #include static char *modes[] = { "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx", }; static void rwx(long m, char *s) { strncpy(s, modes[m], 3); } int dirmodefmt(Fmt *f) { static char buf[16]; ulong m; m = va_arg(f->args, ulong); if(m & DMDIR) buf[0]='d'; else if(m & DMAPPEND) buf[0]='a'; else if(m & DMAUTH) buf[0]='A'; else buf[0]='-'; if(m & DMEXCL) buf[1]='l'; else buf[1]='-'; rwx((m>>6)&7, buf+2); rwx((m>>3)&7, buf+5); rwx((m>>0)&7, buf+8); buf[11] = 0; return fmtstrcpy(f, buf); } drawterm-20170818/libc/dirstat.c000066400000000000000000000012601314554504700163510ustar00rootroot00000000000000#include #include #include enum { DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */ }; Dir* dirstat(char *name) { Dir *d; uchar *buf; int n, nd, i; nd = DIRSIZE; for(i=0; i<2; i++){ /* should work by the second try */ d = malloc(sizeof(Dir) + BIT16SZ + nd); if(d == nil) return nil; buf = (uchar*)&d[1]; n = stat(name, buf, BIT16SZ+nd); if(n < BIT16SZ){ free(d); return nil; } nd = GBIT16((uchar*)buf); /* upper bound on size of Dir + strings */ if(nd <= n){ convM2D(buf, n, d, (char*)&d[1]); return d; } /* else sizeof(Dir)+BIT16SZ+nd is plenty */ free(d); } return nil; } drawterm-20170818/libc/dirwstat.c000066400000000000000000000003661314554504700165460ustar00rootroot00000000000000#include #include #include int dirwstat(char *name, Dir *d) { uchar *buf; int r; r = sizeD2M(d); buf = malloc(r); if(buf == nil) return -1; convD2M(d, buf, r); r = wstat(name, buf, r); free(buf); return r; } drawterm-20170818/libc/dofmt.c000066400000000000000000000216411314554504700160150ustar00rootroot00000000000000#include #include #include "fmtdef.h" /* format the output into f->to and return the number of characters fmted */ int dofmt(Fmt *f, char *fmt) { Rune rune, *rt, *rs; int r; char *t, *s; int n, nfmt; nfmt = f->nfmt; for(;;){ if(f->runes){ rt = (Rune*)f->to; rs = (Rune*)f->stop; while((r = *(uchar*)fmt) && r != '%'){ if(r < Runeself) fmt++; else{ fmt += chartorune(&rune, fmt); r = rune; } FMTRCHAR(f, rt, rs, r); } fmt++; f->nfmt += rt - (Rune *)f->to; f->to = rt; if(!r) return f->nfmt - nfmt; f->stop = rs; }else{ t = (char*)f->to; s = (char*)f->stop; while((r = *(uchar*)fmt) && r != '%'){ if(r < Runeself){ FMTCHAR(f, t, s, r); fmt++; }else{ n = chartorune(&rune, fmt); if(t + n > s){ t = (char*)__fmtflush(f, t, n); if(t != nil) s = (char*)f->stop; else return -1; } while(n--) *t++ = *fmt++; } } fmt++; f->nfmt += t - (char *)f->to; f->to = t; if(!r) return f->nfmt - nfmt; f->stop = s; } fmt = (char*)__fmtdispatch(f, fmt, 0); if(fmt == nil) return -1; } } void * __fmtflush(Fmt *f, void *t, int len) { if(f->runes) f->nfmt += (Rune*)t - (Rune*)f->to; else f->nfmt += (char*)t - (char *)f->to; f->to = t; if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){ f->stop = f->to; return nil; } return f->to; } /* * put a formatted block of memory sz bytes long of n runes into the output buffer, * left/right justified in a field of at least f->width charactes */ int __fmtpad(Fmt *f, int n) { char *t, *s; int i; t = (char*)f->to; s = (char*)f->stop; for(i = 0; i < n; i++) FMTCHAR(f, t, s, ' '); f->nfmt += t - (char *)f->to; f->to = t; return 0; } int __rfmtpad(Fmt *f, int n) { Rune *t, *s; int i; t = (Rune*)f->to; s = (Rune*)f->stop; for(i = 0; i < n; i++) FMTRCHAR(f, t, s, ' '); f->nfmt += t - (Rune *)f->to; f->to = t; return 0; } int __fmtcpy(Fmt *f, const void *vm, int n, int sz) { Rune *rt, *rs, r; char *t, *s, *m, *me; ulong fl; int nc, w; m = (char*)vm; me = m + sz; w = f->width; fl = f->flags; if((fl & FmtPrec) && n > f->prec) n = f->prec; if(f->runes){ if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0) return -1; rt = (Rune*)f->to; rs = (Rune*)f->stop; for(nc = n; nc > 0; nc--){ r = *(uchar*)m; if(r < Runeself) m++; else if((me - m) >= UTFmax || fullrune(m, me-m)) m += chartorune(&r, m); else break; FMTRCHAR(f, rt, rs, r); } f->nfmt += rt - (Rune *)f->to; f->to = rt; if(fl & FmtLeft && __rfmtpad(f, w - n) < 0) return -1; }else{ if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0) return -1; t = (char*)f->to; s = (char*)f->stop; for(nc = n; nc > 0; nc--){ r = *(uchar*)m; if(r < Runeself) m++; else if((me - m) >= UTFmax || fullrune(m, me-m)) m += chartorune(&r, m); else break; FMTRUNE(f, t, s, r); } f->nfmt += t - (char *)f->to; f->to = t; if(fl & FmtLeft && __fmtpad(f, w - n) < 0) return -1; } return 0; } int __fmtrcpy(Fmt *f, const void *vm, int n) { Rune r, *m, *me, *rt, *rs; char *t, *s; ulong fl; int w; m = (Rune*)vm; w = f->width; fl = f->flags; if((fl & FmtPrec) && n > f->prec) n = f->prec; if(f->runes){ if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0) return -1; rt = (Rune*)f->to; rs = (Rune*)f->stop; for(me = m + n; m < me; m++) FMTRCHAR(f, rt, rs, *m); f->nfmt += rt - (Rune *)f->to; f->to = rt; if(fl & FmtLeft && __rfmtpad(f, w - n) < 0) return -1; }else{ if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0) return -1; t = (char*)f->to; s = (char*)f->stop; for(me = m + n; m < me; m++){ r = *m; FMTRUNE(f, t, s, r); } f->nfmt += t - (char *)f->to; f->to = t; if(fl & FmtLeft && __fmtpad(f, w - n) < 0) return -1; } return 0; } /* fmt out one character */ int __charfmt(Fmt *f) { char x[1]; x[0] = va_arg(f->args, int); f->prec = 1; return __fmtcpy(f, (const char*)x, 1, 1); } /* fmt out one rune */ int __runefmt(Fmt *f) { Rune x[1]; x[0] = va_arg(f->args, int); return __fmtrcpy(f, (const void*)x, 1); } /* public helper routine: fmt out a null terminated string already in hand */ int fmtstrcpy(Fmt *f, char *s) { int i, j; Rune r; if(!s) return __fmtcpy(f, "", 5, 5); /* if precision is specified, make sure we don't wander off the end */ if(f->flags & FmtPrec){ i = 0; for(j=0; jprec && s[i]; j++) i += chartorune(&r, s+i); return __fmtcpy(f, s, j, i); } return __fmtcpy(f, s, utflen(s), strlen(s)); } /* fmt out a null terminated utf string */ int __strfmt(Fmt *f) { char *s; s = va_arg(f->args, char *); return fmtstrcpy(f, s); } /* public helper routine: fmt out a null terminated rune string already in hand */ int fmtrunestrcpy(Fmt *f, Rune *s) { Rune *e; int n, p; if(!s) return __fmtcpy(f, "", 5, 5); /* if precision is specified, make sure we don't wander off the end */ if(f->flags & FmtPrec){ p = f->prec; for(n = 0; n < p; n++) if(s[n] == 0) break; }else{ for(e = s; *e; e++) ; n = e - s; } return __fmtrcpy(f, s, n); } /* fmt out a null terminated rune string */ int __runesfmt(Fmt *f) { Rune *s; s = va_arg(f->args, Rune *); return fmtrunestrcpy(f, s); } /* fmt a % */ int __percentfmt(Fmt *f) { Rune x[1]; x[0] = f->r; f->prec = 1; return __fmtrcpy(f, (const void*)x, 1); } /* fmt an integer */ int __ifmt(Fmt *f) { char buf[70], *p, *conv; uvlong vu; ulong u; int neg, base, i, n, fl, w, isv; neg = 0; fl = f->flags; isv = 0; vu = 0; u = 0; /* * Unsigned verbs for ANSI C */ switch(f->r){ case 'x': case 'X': case 'o': case 'u': case 'p': fl |= FmtUnsigned; fl &= ~(FmtSign|FmtSpace); break; } if(f->r == 'p'){ if(sizeof(void*) == sizeof(uvlong)){ isv = 1; vu = (uvlong)va_arg(f->args, uvlong); }else u = (ulong)va_arg(f->args, ulong); f->r = 'x'; fl |= FmtUnsigned; }else if(fl & FmtVLong){ isv = 1; if(fl & FmtUnsigned) vu = va_arg(f->args, uvlong); else vu = va_arg(f->args, vlong); }else if(fl & FmtLong){ if(fl & FmtUnsigned) u = va_arg(f->args, ulong); else u = va_arg(f->args, long); }else if(fl & FmtByte){ if(fl & FmtUnsigned) u = (uchar)va_arg(f->args, int); else u = (char)va_arg(f->args, int); }else if(fl & FmtShort){ if(fl & FmtUnsigned) u = (ushort)va_arg(f->args, int); else u = (short)va_arg(f->args, int); }else{ if(fl & FmtUnsigned) u = va_arg(f->args, uint); else u = va_arg(f->args, int); } conv = "0123456789abcdef"; switch(f->r){ case 'd': case 'i': case 'u': base = 10; break; case 'x': base = 16; break; case 'X': base = 16; conv = "0123456789ABCDEF"; break; case 'b': base = 2; break; case 'o': base = 8; break; default: return -1; } if(!(fl & FmtUnsigned)){ if(isv && (vlong)vu < 0){ vu = -(vlong)vu; neg = 1; }else if(!isv && (long)u < 0){ u = -(long)u; neg = 1; } } p = buf + sizeof buf - 1; n = 0; if(isv){ while(vu){ i = vu % base; vu /= base; if((fl & FmtComma) && n % 4 == 3){ *p-- = ','; n++; } *p-- = conv[i]; n++; } }else{ while(u){ i = u % base; u /= base; if((fl & FmtComma) && n % 4 == 3){ *p-- = ','; n++; } *p-- = conv[i]; n++; } } if(n == 0){ *p-- = '0'; n = 1; } for(w = f->prec; n < w && p > buf+3; n++) *p-- = '0'; if(neg || (fl & (FmtSign|FmtSpace))) n++; if(fl & FmtSharp){ if(base == 16) n += 2; else if(base == 8){ if(p[1] == '0') fl &= ~FmtSharp; else n++; } } if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){ for(w = f->width; n < w && p > buf+3; n++) *p-- = '0'; f->width = 0; } if(fl & FmtSharp){ if(base == 16) *p-- = f->r; if(base == 16 || base == 8) *p-- = '0'; } if(neg) *p-- = '-'; else if(fl & FmtSign) *p-- = '+'; else if(fl & FmtSpace) *p-- = ' '; f->flags &= ~FmtPrec; return __fmtcpy(f, p + 1, n, n); } int __countfmt(Fmt *f) { void *p; ulong fl; fl = f->flags; p = va_arg(f->args, void*); if(fl & FmtVLong){ *(vlong*)p = f->nfmt; }else if(fl & FmtLong){ *(long*)p = f->nfmt; }else if(fl & FmtByte){ *(char*)p = f->nfmt; }else if(fl & FmtShort){ *(short*)p = f->nfmt; }else{ *(int*)p = f->nfmt; } return 0; } int __flagfmt(Fmt *f) { switch(f->r){ case ',': f->flags |= FmtComma; break; case '-': f->flags |= FmtLeft; break; case '+': f->flags |= FmtSign; break; case '#': f->flags |= FmtSharp; break; case ' ': f->flags |= FmtSpace; break; case 'u': f->flags |= FmtUnsigned; break; case 'h': if(f->flags & FmtShort) f->flags |= FmtByte; f->flags |= FmtShort; break; case 'L': f->flags |= FmtLDouble; break; case 'l': if(f->flags & FmtLong) f->flags |= FmtVLong; f->flags |= FmtLong; break; } return 1; } /* default error format */ int __badfmt(Fmt *f) { char x[3]; x[0] = '%'; x[1] = f->r; x[2] = '%'; f->prec = 3; __fmtcpy(f, (const void*)x, 3, 3); return 0; } drawterm-20170818/libc/dorfmt.c000066400000000000000000000014271314554504700161770ustar00rootroot00000000000000#include #include #include "fmtdef.h" /* format the output into f->to and return the number of characters fmted */ int dorfmt(Fmt *f, const Rune *fmt) { Rune *rt, *rs; int r; char *t, *s; int nfmt; nfmt = f->nfmt; for(;;){ if(f->runes){ rt = f->to; rs = f->stop; while((r = *fmt++) && r != '%'){ FMTRCHAR(f, rt, rs, r); } f->nfmt += rt - (Rune *)f->to; f->to = rt; if(!r) return f->nfmt - nfmt; f->stop = rs; }else{ t = f->to; s = f->stop; while((r = *fmt++) && r != '%'){ FMTRUNE(f, t, f->stop, r); } f->nfmt += t - (char *)f->to; f->to = t; if(!r) return f->nfmt - nfmt; f->stop = s; } fmt = __fmtdispatch(f, (Rune*)fmt, 1); if(fmt == nil) return -1; } return 0; /* not reached */ } drawterm-20170818/libc/encodefmt.c000066400000000000000000000021141314554504700166420ustar00rootroot00000000000000#include #include #include int encodefmt(Fmt *f) { char *out; char *buf; int len; int ilen; int rv; uchar *b; char *p; char obuf[64]; // rsc optimization if(!(f->flags&FmtPrec) || f->prec < 1) goto error; b = va_arg(f->args, uchar*); if(b == 0) return fmtstrcpy(f, ""); ilen = f->prec; f->prec = 0; f->flags &= ~FmtPrec; switch(f->r){ case '<': len = (8*ilen+4)/5 + 3; break; case '[': len = (8*ilen+5)/6 + 4; break; case 'H': len = 2*ilen + 1; break; default: goto error; } if(len > sizeof(obuf)){ buf = malloc(len); if(buf == nil) goto error; } else buf = obuf; // convert out = buf; switch(f->r){ case '<': rv = enc32(out, len, b, ilen); break; case '[': rv = enc64(out, len, b, ilen); break; case 'H': rv = enc16(out, len, b, ilen); if(rv >= 0 && (f->flags & FmtLong)) for(p = buf; *p; p++) *p = tolower(*p); break; default: rv = -1; break; } if(rv < 0) goto error; fmtstrcpy(f, buf); if(buf != obuf) free(buf); return 0; error: return fmtstrcpy(f, ""); } drawterm-20170818/libc/fcallfmt.c000066400000000000000000000131541314554504700164740ustar00rootroot00000000000000#include #include #include static uint dumpsome(char*, char*, char*, long); static void fdirconv(char*, char*, Dir*); static char *qidtype(char*, uchar); #define QIDFMT "(%.16llux %lud %s)" int fcallfmt(Fmt *fmt) { Fcall *f; int fid, type, tag, i; char buf[512], tmp[200]; char *p, *e; Dir *d; Qid *q; e = buf+sizeof(buf); f = va_arg(fmt->args, Fcall*); type = f->type; fid = f->fid; tag = f->tag; switch(type){ case Tversion: /* 100 */ seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); break; case Rversion: seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); break; case Tauth: /* 102 */ seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag, f->afid, f->uname, f->aname); break; case Rauth: seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag, f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type)); break; case Tattach: /* 104 */ seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag, fid, f->afid, f->uname, f->aname); break; case Rattach: seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag, f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type)); break; case Rerror: /* 107; 106 (Terror) illegal */ seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename); break; case Tflush: /* 108 */ seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag); break; case Rflush: seprint(buf, e, "Rflush tag %ud", tag); break; case Twalk: /* 110 */ p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname); if(f->nwname <= MAXWELEM) for(i=0; inwname; i++) p = seprint(p, e, "%d:%s ", i, f->wname[i]); break; case Rwalk: p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid); if(f->nwqid <= MAXWELEM) for(i=0; inwqid; i++){ q = &f->wqid[i]; p = seprint(p, e, "%d:" QIDFMT " ", i, q->path, q->vers, qidtype(tmp, q->type)); } break; case Topen: /* 112 */ seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode); break; case Ropen: seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag, f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); break; case Tcreate: /* 114 */ seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode); break; case Rcreate: seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag, f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); break; case Tread: /* 116 */ seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud", tag, fid, f->offset, f->count); break; case Rread: p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count); dumpsome(p, e, f->data, f->count); break; case Twrite: /* 118 */ p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ", tag, fid, f->offset, f->count); dumpsome(p, e, f->data, f->count); break; case Rwrite: seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count); break; case Tclunk: /* 120 */ seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid); break; case Rclunk: seprint(buf, e, "Rclunk tag %ud", tag); break; case Tremove: /* 122 */ seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid); break; case Rremove: seprint(buf, e, "Rremove tag %ud", tag); break; case Tstat: /* 124 */ seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid); break; case Rstat: p = seprint(buf, e, "Rstat tag %ud ", tag); if(f->nstat > sizeof tmp) seprint(p, e, " stat(%d bytes)", f->nstat); else{ d = (Dir*)tmp; convM2D(f->stat, f->nstat, d, (char*)(d+1)); seprint(p, e, " stat "); fdirconv(p+6, e, d); } break; case Twstat: /* 126 */ p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid); if(f->nstat > sizeof tmp) seprint(p, e, " stat(%d bytes)", f->nstat); else{ d = (Dir*)tmp; convM2D(f->stat, f->nstat, d, (char*)(d+1)); seprint(p, e, " stat "); fdirconv(p+6, e, d); } break; case Rwstat: seprint(buf, e, "Rwstat tag %ud", tag); break; default: seprint(buf, e, "unknown type %d", type); } return fmtstrcpy(fmt, buf); } static char* qidtype(char *s, uchar t) { char *p; p = s; if(t & QTDIR) *p++ = 'd'; if(t & QTAPPEND) *p++ = 'a'; if(t & QTEXCL) *p++ = 'l'; if(t & QTAUTH) *p++ = 'A'; *p = '\0'; return s; } int dirfmt(Fmt *fmt) { char buf[160]; fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*)); return fmtstrcpy(fmt, buf); } static void fdirconv(char *buf, char *e, Dir *d) { char tmp[16]; seprint(buf, e, "'%s' '%s' '%s' '%s' " "q " QIDFMT " m %#luo " "at %ld mt %ld l %lld " "t %d d %d", d->name, d->uid, d->gid, d->muid, d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode, d->atime, d->mtime, d->length, d->type, d->dev); } /* * dump out count (or DUMPL, if count is bigger) bytes from * buf to ans, as a string if they are all printable, * else as a series of hex bytes */ #define DUMPL 64 static uint dumpsome(char *ans, char *e, char *buf, long count) { int i, printable; char *p; if(buf == nil){ seprint(ans, e, ""); return strlen(ans); } printable = 1; if(count > DUMPL) count = DUMPL; for(i=0; i127) printable = 0; p = ans; *p++ = '\''; if(printable){ if(count > e-p-2) count = e-p-2; memmove(p, buf, count); p += count; }else{ if(2*count > e-p-2) count = (e-p-2)/2; for(i=0; i0 && i%4==0) *p++ = ' '; sprint(p, "%2.2ux", buf[i]); p += 2; } } *p++ = '\''; *p = 0; return p - ans; } drawterm-20170818/libc/fltfmt.c000066400000000000000000000142361314554504700162020ustar00rootroot00000000000000#include #include #include #include #include "fmtdef.h" enum { FDIGIT = 30, FDEFLT = 6, NSIGNIF = 17 }; /* * first few powers of 10, enough for about 1/2 of the * total space for doubles. */ static double pows10[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49, 1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59, 1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69, 1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79, 1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89, 1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, 1e98, 1e99, 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109, 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119, 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129, 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139, 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, }; #undef pow10 #define pow10(x) fmtpow10(x) static double pow10(int n) { double d; int neg; neg = 0; if(n < 0){ if(n < DBL_MIN_10_EXP){ return 0.; } neg = 1; n = -n; }else if(n > DBL_MAX_10_EXP){ return HUGE_VAL; } if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))) d = pows10[n]; else{ d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1]; for(;;){ n -= sizeof(pows10)/sizeof(pows10[0]) - 1; if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){ d *= pows10[n]; break; } d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1]; } } if(neg){ return 1./d; } return d; } static int xadd(char *a, int n, int v) { char *b; int c; if(n < 0 || n >= NSIGNIF) return 0; for(b = a+n; b >= a; b--) { c = *b + v; if(c <= '9') { *b = c; return 0; } *b = '0'; v = 1; } *a = '1'; /* overflow adding */ return 1; } static int xsub(char *a, int n, int v) { char *b; int c; for(b = a+n; b >= a; b--) { c = *b - v; if(c >= '0') { *b = c; return 0; } *b = '9'; v = 1; } *a = '9'; /* underflow subtracting */ return 1; } static void xdtoa(Fmt *fmt, char *s2, double f) { char s1[NSIGNIF+10]; double g, h; int e, d, i, n; int c1, c2, c3, c4, ucase, sign, chr, prec; prec = FDEFLT; if(fmt->flags & FmtPrec) prec = fmt->prec; if(prec > FDIGIT) prec = FDIGIT; if(__isNaN(f)) { strcpy(s2, "NaN"); return; } if(__isInf(f, 1)) { strcpy(s2, "+Inf"); return; } if(__isInf(f, -1)) { strcpy(s2, "-Inf"); return; } sign = 0; if(f < 0) { f = -f; sign++; } ucase = 0; chr = fmt->r; if(isupper(chr)) { ucase = 1; chr = tolower(chr); } e = 0; g = f; if(g != 0) { frexp(f, &e); e = e * .301029995664; if(e >= -150 && e <= +150) { d = 0; h = f; } else { d = e/2; h = f * pow10(-d); } g = h * pow10(d-e); while(g < 1) { e--; g = h * pow10(d-e); } while(g >= 10) { e++; g = h * pow10(d-e); } } /* * convert NSIGNIF digits and convert * back to get accuracy. */ for(i=0; i= NSIGNIF-2) { strcpy(s2, s1); d = e; s1[NSIGNIF-2] = '0'; s1[NSIGNIF-1] = '0'; sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); g = strtod(s1, nil); if(g == f) goto found; if(xadd(s1, NSIGNIF-3, 1)) { e++; sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); } g = strtod(s1, nil); if(g == f) goto found; strcpy(s1, s2); e = d; } /* * convert back so s1 gets exact answer */ for(;;) { sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); g = strtod(s1, nil); if(f > g) { if(xadd(s1, NSIGNIF-1, 1)) e--; continue; } if(f < g) { if(xsub(s1, NSIGNIF-1, 1)) e++; continue; } break; } found: /* * sign */ d = 0; i = 0; if(sign) s2[d++] = '-'; else if(fmt->flags & FmtSign) s2[d++] = '+'; else if(fmt->flags & FmtSpace) s2[d++] = ' '; /* * copy into final place * c1 digits of leading '0' * c2 digits from conversion * c3 digits of trailing '0' * c4 digits after '.' */ c1 = 0; c2 = prec + 1; c3 = 0; c4 = prec; switch(chr) { default: if(xadd(s1, c2, 5)) e++; break; case 'g': /* * decide on 'e' of 'f' style convers */ if(xadd(s1, c2, 5)) e++; if(e >= -5 && e <= prec) { c1 = -e - 1; c4 = prec - e; chr = 'h'; // flag for 'f' style } break; case 'f': if(xadd(s1, c2+e, 5)) e++; c1 = -e; if(c1 > prec) c1 = c2; c2 += e; break; } /* * clean up c1 c2 and c3 */ if(c1 < 0) c1 = 0; if(c2 < 0) c2 = 0; if(c2 > NSIGNIF) { c3 = c2-NSIGNIF; c2 = NSIGNIF; } /* * copy digits */ while(c1 > 0) { if(c1+c2+c3 == c4) s2[d++] = '.'; s2[d++] = '0'; c1--; } while(c2 > 0) { if(c2+c3 == c4) s2[d++] = '.'; s2[d++] = s1[i++]; c2--; } while(c3 > 0) { if(c3 == c4) s2[d++] = '.'; s2[d++] = '0'; c3--; } /* * strip trailing '0' on g conv */ if(fmt->flags & FmtSharp) { if(0 == c4) s2[d++] = '.'; } else if(chr == 'g' || chr == 'h') { for(n=d-1; n>=0; n--) if(s2[n] != '0') break; for(i=n; i>=0; i--) if(s2[i] == '.') { d = n; if(i != n) d++; break; } } if(chr == 'e' || chr == 'g') { if(ucase) s2[d++] = 'E'; else s2[d++] = 'e'; c1 = e; if(c1 < 0) { s2[d++] = '-'; c1 = -c1; } else s2[d++] = '+'; if(c1 >= 100) { s2[d++] = c1/100 + '0'; c1 = c1%100; } s2[d++] = c1/10 + '0'; s2[d++] = c1%10 + '0'; } s2[d] = 0; } static int floatfmt(Fmt *fmt, double f) { char s[341]; /* precision+exponent+sign+'.'+null */ xdtoa(fmt, s, f); fmt->flags &= FmtWidth|FmtLeft; __fmtcpy(fmt, s, strlen(s), strlen(s)); return 0; } int __efgfmt(Fmt *f) { double d; d = va_arg(f->args, double); return floatfmt(f, d); } drawterm-20170818/libc/fmt.c000066400000000000000000000065601314554504700154750ustar00rootroot00000000000000#include #include #include "fmtdef.h" enum { Maxfmt = 64 }; typedef struct Convfmt Convfmt; struct Convfmt { int c; volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */ }; struct { /* lock by calling __fmtlock, __fmtunlock */ int nfmt; Convfmt fmt[Maxfmt]; } fmtalloc; static Convfmt knownfmt[] = { ' ', __flagfmt, '#', __flagfmt, '%', __percentfmt, '+', __flagfmt, ',', __flagfmt, '-', __flagfmt, 'C', __runefmt, /* Plan 9 addition */ 'E', __efgfmt, #ifndef PLAN9PORT 'F', __efgfmt, /* ANSI only */ #endif 'G', __efgfmt, #ifndef PLAN9PORT 'L', __flagfmt, /* ANSI only */ #endif 'S', __runesfmt, /* Plan 9 addition */ 'X', __ifmt, 'b', __ifmt, /* Plan 9 addition */ 'c', __charfmt, 'd', __ifmt, 'e', __efgfmt, 'f', __efgfmt, 'g', __efgfmt, 'h', __flagfmt, #ifndef PLAN9PORT 'i', __ifmt, /* ANSI only */ #endif 'l', __flagfmt, 'n', __countfmt, 'o', __ifmt, 'p', __ifmt, 'r', __errfmt, 's', __strfmt, #ifdef PLAN9PORT 'u', __flagfmt, #else 'u', __ifmt, #endif 'x', __ifmt, 0, 0, }; int (*fmtdoquote)(int); /* * __fmtlock() must be set */ static int __fmtinstall(int c, Fmts f) { Convfmt *p, *ep; if(c<=0 || c>=65536) return -1; if(!f) f = __badfmt; ep = &fmtalloc.fmt[fmtalloc.nfmt]; for(p=fmtalloc.fmt; pc == c) break; if(p == &fmtalloc.fmt[Maxfmt]) return -1; p->fmt = f; if(p == ep){ /* installing a new format character */ fmtalloc.nfmt++; p->c = c; } return 0; } int fmtinstall(int c, int (*f)(Fmt*)) { int ret; __fmtlock(); ret = __fmtinstall(c, f); __fmtunlock(); return ret; } static Fmts fmtfmt(int c) { Convfmt *p, *ep; ep = &fmtalloc.fmt[fmtalloc.nfmt]; for(p=fmtalloc.fmt; pc == c){ while(p->fmt == 0) /* loop until value is updated */ ; return p->fmt; } /* is this a predefined format char? */ __fmtlock(); for(p=knownfmt; p->c; p++) if(p->c == c){ __fmtinstall(p->c, p->fmt); __fmtunlock(); return p->fmt; } __fmtunlock(); return __badfmt; } void* __fmtdispatch(Fmt *f, void *fmt, int isrunes) { Rune rune, r; int i, n; f->flags = 0; f->width = f->prec = 0; for(;;){ if(isrunes){ r = *(Rune*)fmt; fmt = (Rune*)fmt + 1; }else{ fmt = (char*)fmt + chartorune(&rune, (char*)fmt); r = rune; } f->r = r; switch(r){ case '\0': return nil; case '.': f->flags |= FmtWidth|FmtPrec; continue; case '0': if(!(f->flags & FmtWidth)){ f->flags |= FmtZero; continue; } /* fall through */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': i = 0; while(r >= '0' && r <= '9'){ i = i * 10 + r - '0'; if(isrunes){ r = *(Rune*)fmt; fmt = (Rune*)fmt + 1; }else{ r = *(char*)fmt; fmt = (char*)fmt + 1; } } if(isrunes) fmt = (Rune*)fmt - 1; else fmt = (char*)fmt - 1; numflag: if(f->flags & FmtWidth){ f->flags |= FmtPrec; f->prec = i; }else{ f->flags |= FmtWidth; f->width = i; } continue; case '*': i = va_arg(f->args, int); if(i < 0){ /* * negative precision => * ignore the precision. */ if(f->flags & FmtPrec){ f->flags &= ~FmtPrec; f->prec = 0; continue; } i = -i; f->flags |= FmtLeft; } goto numflag; } n = (*fmtfmt(r))(f); if(n < 0) return nil; if(n == 0) return fmt; } } drawterm-20170818/libc/fmtdef.h000066400000000000000000000052321314554504700161540ustar00rootroot00000000000000/* * dofmt -- format to a buffer * the number of characters formatted is returned, * or -1 if there was an error. * if the buffer is ever filled, flush is called. * it should reset the buffer and return whether formatting should continue. */ typedef int (*Fmts)(Fmt*); typedef struct Quoteinfo Quoteinfo; struct Quoteinfo { int quoted; /* if set, string must be quoted */ int nrunesin; /* number of input runes that can be accepted */ int nbytesin; /* number of input bytes that can be accepted */ int nrunesout; /* number of runes that will be generated */ int nbytesout; /* number of bytes that will be generated */ }; /* Edit .+1,/^$/ |cfn |grep -v static | grep __ */ double __Inf(int sign); double __NaN(void); int __badfmt(Fmt *f); int __charfmt(Fmt *f); int __countfmt(Fmt *f); int __efgfmt(Fmt *fmt); int __errfmt(Fmt *f); int __flagfmt(Fmt *f); int __fmtFdFlush(Fmt *f); int __fmtcpy(Fmt *f, const void *vm, int n, int sz); void* __fmtdispatch(Fmt *f, void *fmt, int isrunes); void * __fmtflush(Fmt *f, void *t, int len); void __fmtlock(void); int __fmtpad(Fmt *f, int n); double __fmtpow10(int n); int __fmtrcpy(Fmt *f, const void *vm, int n); void __fmtunlock(void); int __ifmt(Fmt *f); int __isInf(double d, int sign); int __isNaN(double d); int __needsquotes(char *s, int *quotelenp); int __percentfmt(Fmt *f); void __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout); int __quotestrfmt(int runesin, Fmt *f); int __rfmtpad(Fmt *f, int n); int __runefmt(Fmt *f); int __runeneedsquotes(Rune *r, int *quotelenp); int __runesfmt(Fmt *f); int __strfmt(Fmt *f); #define FMTCHAR(f, t, s, c)\ do{\ if(t + 1 > (char*)s){\ t = __fmtflush(f, t, 1);\ if(t != nil)\ s = f->stop;\ else\ return -1;\ }\ *t++ = c;\ }while(0) #define FMTRCHAR(f, t, s, c)\ do{\ if(t + 1 > (Rune*)s){\ t = __fmtflush(f, t, sizeof(Rune));\ if(t != nil)\ s = f->stop;\ else\ return -1;\ }\ *t++ = c;\ }while(0) #define FMTRUNE(f, t, s, r)\ do{\ Rune _rune;\ int _runelen;\ if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\ t = __fmtflush(f, t, _runelen);\ if(t != nil)\ s = f->stop;\ else\ return -1;\ }\ if(r < Runeself)\ *t++ = r;\ else{\ _rune = r;\ t += runetochar(t, &_rune);\ }\ }while(0) #ifdef va_copy # define VA_COPY(a,b) va_copy(a,b) # define VA_END(a) va_end(a) #else # define VA_COPY(a,b) (a) = (b) # define VA_END(a) #endif #define PLAN9PORT drawterm-20170818/libc/fmtfd.c000066400000000000000000000010371314554504700160010ustar00rootroot00000000000000#include #include #include #include "fmtdef.h" /* * public routine for final flush of a formatting buffer * to a file descriptor; returns total char count. */ int fmtfdflush(Fmt *f) { if(__fmtFdFlush(f) <= 0) return -1; return f->nfmt; } /* * initialize an output buffer for buffered printing */ int fmtfdinit(Fmt *f, int fd, char *buf, int size) { f->runes = 0; f->start = buf; f->to = buf; f->stop = buf + size; f->flush = __fmtFdFlush; f->farg = (void*)(uintptr_t)fd; f->nfmt = 0; return 0; } drawterm-20170818/libc/fmtfdflush.c000066400000000000000000000005121314554504700170400ustar00rootroot00000000000000#include #include #include #include "fmtdef.h" /* * generic routine for flushing a formatting buffer * to a file descriptor */ int __fmtFdFlush(Fmt *f) { int n; n = (char*)f->to - (char*)f->start; if(n && write((uintptr_t)f->farg, f->start, n) != n) return 0; f->to = f->start; return 1; } drawterm-20170818/libc/fmtlock.c000066400000000000000000000002101314554504700163300ustar00rootroot00000000000000#include #include static Lock fmtl; void __fmtlock(void) { lock(&fmtl); } void __fmtunlock(void) { unlock(&fmtl); } drawterm-20170818/libc/fmtprint.c000066400000000000000000000007761314554504700165550ustar00rootroot00000000000000#include #include #include "fmtdef.h" /* * format a string into the output buffer * designed for formats which themselves call fmt, * but ignore any width flags */ int fmtprint(Fmt *f, char *fmt, ...) { va_list va; int n; f->flags = 0; f->width = 0; f->prec = 0; VA_COPY(va, f->args); VA_END(f->args); va_start(f->args, fmt); n = dofmt(f, fmt); va_end(f->args); f->flags = 0; f->width = 0; f->prec = 0; VA_COPY(f->args,va); VA_END(va); if(n >= 0) return 0; return n; } drawterm-20170818/libc/fmtquote.c000066400000000000000000000112311314554504700165420ustar00rootroot00000000000000#include #include #include "fmtdef.h" /* * How many bytes of output UTF will be produced by quoting (if necessary) this string? * How many runes? How much of the input will be consumed? * The parameter q is filled in by __quotesetup. * The string may be UTF or Runes (s or r). * Return count does not include NUL. * Terminate the scan at the first of: * NUL in input * count exceeded in input * count exceeded on output * *ninp is set to number of input bytes accepted. * nin may be <0 initially, to avoid checking input by count. */ void __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout) { int w; Rune c; q->quoted = 0; q->nbytesout = 0; q->nrunesout = 0; q->nbytesin = 0; q->nrunesin = 0; if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){ if(nout < 2) return; q->quoted = 1; q->nbytesout = 2; q->nrunesout = 2; } for(; nin!=0; nin--){ if(s) w = chartorune(&c, s); else{ c = *r; w = runelen(c); } if(c == '\0') break; if(runesout){ if(q->nrunesout+1 > nout) break; }else{ if(q->nbytesout+w > nout) break; } if((c <= L' ') || (c == L'\'') || (fmtdoquote!=0 && fmtdoquote(c))){ if(!q->quoted){ if(runesout){ if(1+q->nrunesout+1+1 > nout) /* no room for quotes */ break; }else{ if(1+q->nbytesout+w+1 > nout) /* no room for quotes */ break; } q->nrunesout += 2; /* include quotes */ q->nbytesout += 2; /* include quotes */ q->quoted = 1; } if(c == '\'') { if(runesout){ if(1+q->nrunesout+1 > nout) /* no room for quotes */ break; }else{ if(1+q->nbytesout+w > nout) /* no room for quotes */ break; } q->nbytesout++; q->nrunesout++; /* quotes reproduce as two characters */ } } /* advance input */ if(s) s += w; else r++; q->nbytesin += w; q->nrunesin++; /* advance output */ q->nbytesout += w; q->nrunesout++; } } static int qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f) { Rune r, *rm, *rme; char *t, *s, *m, *me; Rune *rt, *rs; ulong fl; int nc, w; m = sin; me = m + q->nbytesin; rm = rin; rme = rm + q->nrunesin; w = f->width; fl = f->flags; if(f->runes){ if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0) return -1; }else{ if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0) return -1; } t = (char*)f->to; s = (char*)f->stop; rt = (Rune*)f->to; rs = (Rune*)f->stop; if(f->runes) FMTRCHAR(f, rt, rs, '\''); else FMTRUNE(f, t, s, '\''); for(nc = q->nrunesin; nc > 0; nc--){ if(sin){ r = *(uchar*)m; if(r < Runeself) m++; else if((me - m) >= UTFmax || fullrune(m, me-m)) m += chartorune(&r, m); else break; }else{ if(rm >= rme) break; r = *(uchar*)rm++; } if(f->runes){ FMTRCHAR(f, rt, rs, r); if(r == '\'') FMTRCHAR(f, rt, rs, r); }else{ FMTRUNE(f, t, s, r); if(r == '\'') FMTRUNE(f, t, s, r); } } if(f->runes){ FMTRCHAR(f, rt, rs, '\''); USED(rs); f->nfmt += rt - (Rune *)f->to; f->to = rt; if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0) return -1; }else{ FMTRUNE(f, t, s, '\''); USED(s); f->nfmt += t - (char *)f->to; f->to = t; if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0) return -1; } return 0; } int __quotestrfmt(int runesin, Fmt *f) { int nin, outlen; Rune *r; char *s; Quoteinfo q; nin = -1; if(f->flags&FmtPrec) nin = f->prec; if(runesin){ r = va_arg(f->args, Rune *); s = nil; }else{ s = va_arg(f->args, char *); r = nil; } if(!s && !r) return __fmtcpy(f, (void*)"", 5, 5); if(f->flush) outlen = 0x7FFFFFFF; /* if we can flush, no output limit */ else if(f->runes) outlen = (Rune*)f->stop - (Rune*)f->to; else outlen = (char*)f->stop - (char*)f->to; __quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes); //print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); if(runesin){ if(!q.quoted) return __fmtrcpy(f, r, q.nrunesin); return qstrfmt(nil, r, &q, f); } if(!q.quoted) return __fmtcpy(f, s, q.nrunesin, q.nbytesin); return qstrfmt(s, nil, &q, f); } int quotestrfmt(Fmt *f) { return __quotestrfmt(0, f); } int quoterunestrfmt(Fmt *f) { return __quotestrfmt(1, f); } void quotefmtinstall(void) { fmtinstall('q', quotestrfmt); fmtinstall('Q', quoterunestrfmt); } int __needsquotes(char *s, int *quotelenp) { Quoteinfo q; __quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0); *quotelenp = q.nbytesout; return q.quoted; } int __runeneedsquotes(Rune *r, int *quotelenp) { Quoteinfo q; __quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0); *quotelenp = q.nrunesout; return q.quoted; } drawterm-20170818/libc/fmtrune.c000066400000000000000000000005101314554504700163540ustar00rootroot00000000000000#include #include #include "fmtdef.h" int fmtrune(Fmt *f, int r) { Rune *rt; char *t; int n; if(f->runes){ rt = (Rune*)f->to; FMTRCHAR(f, rt, f->stop, r); f->to = rt; n = 1; }else{ t = (char*)f->to; FMTRUNE(f, t, f->stop, r); n = t - (char*)f->to; f->to = t; } f->nfmt += n; return 0; } drawterm-20170818/libc/fmtstr.c000066400000000000000000000002471314554504700162220ustar00rootroot00000000000000#include #include #include "fmtdef.h" char* fmtstrflush(Fmt *f) { if(f->start == nil) return nil; *(char*)f->to = '\0'; return (char*)f->start; } drawterm-20170818/libc/fmtvprint.c000066400000000000000000000010071314554504700167270ustar00rootroot00000000000000#include #include #include "fmtdef.h" /* * format a string into the output buffer * designed for formats which themselves call fmt, * but ignore any width flags */ int fmtvprint(Fmt *f, char *fmt, va_list args) { va_list va; int n; f->flags = 0; f->width = 0; f->prec = 0; VA_COPY(va,f->args); VA_END(f->args); VA_COPY(f->args,args); n = dofmt(f, fmt); f->flags = 0; f->width = 0; f->prec = 0; VA_END(f->args); VA_COPY(f->args,va); VA_END(va); if(n >= 0) return 0; return n; } drawterm-20170818/libc/fprint.c000066400000000000000000000003021314554504700161750ustar00rootroot00000000000000#include #include #include "fmtdef.h" int fprint(int fd, char *fmt, ...) { int n; va_list args; va_start(args, fmt); n = vfprint(fd, fmt, args); va_end(args); return n; } drawterm-20170818/libc/frand.c000066400000000000000000000003221314554504700157670ustar00rootroot00000000000000#include #include #define MASK 0x7fffffffL #define NORM (1.0/(1.0+MASK)) double frand(void) { double x; do { x = lrand() * NORM; x = (x + lrand()) * NORM; } while(x >= 1); return x; } drawterm-20170818/libc/getfields.c000066400000000000000000000010041314554504700166410ustar00rootroot00000000000000#include #include int getfields(char *str, char **args, int max, int mflag, char *set) { Rune r; int nr, intok, narg; if(max <= 0) return 0; narg = 0; args[narg] = str; if(!mflag) narg++; intok = 0; for(;; str += nr) { nr = chartorune(&r, str); if(r == 0) break; if(utfrune(set, r)) { if(narg >= max) break; *str = 0; intok = 0; args[narg] = str + nr; if(!mflag) narg++; } else { if(!intok && mflag) narg++; intok = 1; } } return narg; } drawterm-20170818/libc/getpid.c000066400000000000000000000003061314554504700161530ustar00rootroot00000000000000#include #include int getpid(void) { char b[20]; int f; memset(b, 0, sizeof(b)); f = open("#c/pid", 0); if(f >= 0) { read(f, b, sizeof(b)); close(f); } return atol(b); } drawterm-20170818/libc/lnrand.c000066400000000000000000000003021314554504700161510ustar00rootroot00000000000000#include #include #define MASK 0x7fffffffL long lnrand(long n) { long slop, v; if(n < 0) return n; slop = MASK % n; do v = lrand(); while(v <= slop); return v % n; } drawterm-20170818/libc/lock.c000066400000000000000000000030741314554504700156340ustar00rootroot00000000000000#include #include #ifdef PTHREAD static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER; static void lockinit(Lock *lk) { pthread_mutexattr_t attr; pthread_mutex_lock(&initmutex); if(lk->init == 0){ pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); pthread_mutex_init(&lk->mutex, &attr); pthread_mutexattr_destroy(&attr); lk->init = 1; } pthread_mutex_unlock(&initmutex); } void lock(Lock *lk) { if(!lk->init) lockinit(lk); if(pthread_mutex_lock(&lk->mutex) != 0) abort(); } int canlock(Lock *lk) { int r; if(!lk->init) lockinit(lk); r = pthread_mutex_trylock(&lk->mutex); if(r == 0) return 1; if(r == EBUSY) return 0; abort(); } void unlock(Lock *lk) { if(pthread_mutex_unlock(&lk->mutex) != 0) abort(); } #else /* old, non-pthread systems */ int canlock(Lock *lk) { return !tas(&lk->key); } void lock(Lock *lk) { int i; /* easy case */ if(canlock(lk)) return; /* for multi processor machines */ for(i=0; i<100; i++) if(canlock(lk)) return; for(i=0; i<100; i++) { osyield(); if(canlock(lk)) return; } /* looking bad - make sure it is not a priority problem */ for(i=0; i<12; i++) { osmsleep(1<key, lk, getcallerpc(&lk)); osmsleep(1000); } } void unlock(Lock *lk) { assert(lk->key); lk->key = 0; } #endif void ilock(Lock *lk) { lock(lk); } void iunlock(Lock *lk) { unlock(lk); } drawterm-20170818/libc/lrand.c000066400000000000000000000021251314554504700160000ustar00rootroot00000000000000#include #include /* * algorithm by * D. P. Mitchell & J. A. Reeds */ #define LEN 607 #define TAP 273 #define MASK 0x7fffffffL #define A 48271 #define M 2147483647 #define Q 44488 #define R 3399 #define NORM (1.0/(1.0+MASK)) static ulong rng_vec[LEN]; static ulong* rng_tap = rng_vec; static ulong* rng_feed = 0; static Lock lk; static void isrand(long seed) { long lo, hi, x; int i; rng_tap = rng_vec; rng_feed = rng_vec+LEN-TAP; seed = seed%M; if(seed < 0) seed += M; if(seed == 0) seed = 89482311; x = seed; /* * Initialize by x[n+1] = 48271 * x[n] mod (2**31 - 1) */ for(i = -20; i < LEN; i++) { hi = x / Q; lo = x % Q; x = A*lo - R*hi; if(x < 0) x += M; if(i >= 0) rng_vec[i] = x; } } void srand(long seed) { lock(&lk); isrand(seed); unlock(&lk); } long lrand(void) { ulong x; lock(&lk); rng_tap--; if(rng_tap < rng_vec) { if(rng_feed == 0) { isrand(1); rng_tap--; } rng_tap += LEN; } rng_feed--; if(rng_feed < rng_vec) rng_feed += LEN; x = (*rng_feed + *rng_tap) & MASK; *rng_feed = x; unlock(&lk); return x; } drawterm-20170818/libc/mallocz.c000066400000000000000000000002151314554504700163370ustar00rootroot00000000000000#include #include void* mallocz(ulong n, int clr) { void *v; v = malloc(n); if(v && clr) memset(v, 0, n); return v; } drawterm-20170818/libc/nan.h000066400000000000000000000001621314554504700154600ustar00rootroot00000000000000extern double __NaN(void); extern double __Inf(int); extern int __isNaN(double); extern int __isInf(double, int); drawterm-20170818/libc/nan64.c000066400000000000000000000020331314554504700156240ustar00rootroot00000000000000/* * 64-bit IEEE not-a-number routines. * This is big/little-endian portable assuming that * the 64-bit doubles and 64-bit integers have the * same byte ordering. */ #include #include #include "fmtdef.h" #if defined (__APPLE__) || (__powerpc__) #define _NEEDLL #endif static uvlong uvnan = ((uvlong)0x7FF00000<<32)|0x00000001; static uvlong uvinf = ((uvlong)0x7FF00000<<32)|0x00000000; static uvlong uvneginf = ((uvlong)0xFFF00000<<32)|0x00000000; double __NaN(void) { uvlong *p; /* gcc complains about "return *(double*)&uvnan;" */ p = &uvnan; return *(double*)p; } int __isNaN(double d) { uvlong x; double *p; p = &d; x = *(uvlong*)p; return (ulong)(x>>32)==0x7FF00000 && !__isInf(d, 0); } double __Inf(int sign) { uvlong *p; if(sign < 0) p = &uvinf; else p = &uvneginf; return *(double*)p; } int __isInf(double d, int sign) { uvlong x; double *p; p = &d; x = *(uvlong*)p; if(sign == 0) return x==uvinf || x==uvneginf; else if(sign > 0) return x==uvinf; else return x==uvneginf; } drawterm-20170818/libc/netmkaddr.c000066400000000000000000000015371314554504700166570ustar00rootroot00000000000000#include #include #include /* * make an address, add the defaults */ char * netmkaddr(char *linear, char *defnet, char *defsrv) { static char addr[256]; char *cp; /* * dump network name */ cp = strchr(linear, '!'); if(cp == 0){ if(defnet==0){ if(defsrv) snprint(addr, sizeof(addr), "net!%s!%s", linear, defsrv); else snprint(addr, sizeof(addr), "net!%s", linear); } else { if(defsrv) snprint(addr, sizeof(addr), "%s!%s!%s", defnet, linear, defsrv); else snprint(addr, sizeof(addr), "%s!%s", defnet, linear); } return addr; } /* * if there is already a service, use it */ cp = strchr(cp+1, '!'); if(cp) return linear; /* * add default service */ if(defsrv == 0) return linear; snprint(addr, sizeof(addr), "%s!%s", linear, defsrv); return addr; } drawterm-20170818/libc/nrand.c000066400000000000000000000002771314554504700160100ustar00rootroot00000000000000#include #include #define MASK 0x7fffffffL int nrand(int n) { long slop, v; if(n < 0) return n; slop = MASK % n; do v = lrand(); while(v <= slop); return v % n; } drawterm-20170818/libc/nsec.c000066400000000000000000000022541314554504700156330ustar00rootroot00000000000000#include #include static uvlong order = (uvlong) 0x0001020304050607ULL; static void be2vlong(vlong *to, uchar *f) { uchar *t, *o; int i; t = (uchar*)to; o = (uchar*)ℴ for(i = 0; i < 8; i++) t[o[i]] = f[i]; } /* * After a fork with fd's copied, both fd's are pointing to * the same Chan structure. Since the offset is kept in the Chan * structure, the seek's and read's in the two processes can * compete at moving the offset around. Hence the retry loop. * * Since the bintime version doesn't need a seek, it doesn't * have the loop. */ vlong nsec(void) { char b[12+1]; static int f = -1; static int usebintime; int retries; vlong t; if(f < 0){ usebintime = 1; f = open("/dev/bintime", OREAD|OCEXEC); if(f < 0){ usebintime = 0; f = open("/dev/nsec", OREAD|OCEXEC); if(f < 0) return 0; } } if(usebintime){ if(read(f, b, sizeof(uvlong)) < 0) goto error; be2vlong(&t, (uchar*)b); return t; } else { for(retries = 0; retries < 100; retries++){ if(seek(f, 0, 0) >= 0 && read(f, b, sizeof(b)-1) >= 0){ b[sizeof(b)-1] = 0; return strtoll(b, 0, 0); } } } error: close(f); f = -1; return 0; } drawterm-20170818/libc/pow10.c000066400000000000000000000022531314554504700156500ustar00rootroot00000000000000#include #include #include "fmtdef.h" /* * this table might overflow 127-bit exponent representations. * in that case, truncate it after 1.0e38. * it is important to get all one can from this * routine since it is used in atof to scale numbers. * the presumption is that C converts fp numbers better * than multipication of lower powers of 10. */ static double tab[] = { 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10,1.0e11,1.0e12,1.0e13,1.0e14,1.0e15,1.0e16,1.0e17,1.0e18,1.0e19, 1.0e20,1.0e21,1.0e22,1.0e23,1.0e24,1.0e25,1.0e26,1.0e27,1.0e28,1.0e29, 1.0e30,1.0e31,1.0e32,1.0e33,1.0e34,1.0e35,1.0e36,1.0e37,1.0e38,1.0e39, 1.0e40,1.0e41,1.0e42,1.0e43,1.0e44,1.0e45,1.0e46,1.0e47,1.0e48,1.0e49, 1.0e50,1.0e51,1.0e52,1.0e53,1.0e54,1.0e55,1.0e56,1.0e57,1.0e58,1.0e59, 1.0e60,1.0e61,1.0e62,1.0e63,1.0e64,1.0e65,1.0e66,1.0e67,1.0e68,1.0e69, }; double __fmtpow10(int n) { int m; if(n < 0) { n = -n; if(n < (int)(sizeof(tab)/sizeof(tab[0]))) return 1/tab[n]; m = n/2; return __fmtpow10(-m) * __fmtpow10(m-n); } if(n < (int)(sizeof(tab)/sizeof(tab[0]))) return tab[n]; m = n/2; return __fmtpow10(m) * __fmtpow10(n-m); } drawterm-20170818/libc/print.c000066400000000000000000000002701314554504700160330ustar00rootroot00000000000000#include #include #include "fmtdef.h" int print(char *fmt, ...) { int n; va_list args; va_start(args, fmt); n = vfprint(1, fmt, args); va_end(args); return n; } drawterm-20170818/libc/pushssl.c000066400000000000000000000016111314554504700164000ustar00rootroot00000000000000#include #include /* * Since the SSL device uses decimal file descriptors to name channels, * it is impossible for a user-level file server to stand in for the kernel device. * Thus we hard-code #D rather than use /net/ssl. */ int pushssl(int fd, char *alg, char *secin, char *secout, int *cfd) { char buf[8]; char dname[64]; int n, data, ctl; ctl = open("#D/ssl/clone", ORDWR); if(ctl < 0) return -1; n = read(ctl, buf, sizeof(buf)-1); if(n < 0) goto error; buf[n] = 0; sprint(dname, "#D/ssl/%s/data", buf); data = open(dname, ORDWR); if(data < 0) goto error; if(fprint(ctl, "fd %d", fd) < 0 || fprint(ctl, "secretin %s", secin) < 0 || fprint(ctl, "secretout %s", secout) < 0 || fprint(ctl, "alg %s", alg) < 0){ close(data); goto error; } close(fd); if(cfd != 0) *cfd = ctl; else close(ctl); return data; error: close(ctl); return -1; } drawterm-20170818/libc/pushtls.c000066400000000000000000000037471314554504700164150ustar00rootroot00000000000000#include #include #include #include #include enum { TLSFinishedLen = 12, HFinished = 20, }; static int finished(int hand, int isclient) { int i, n; uchar buf[500], buf2[500]; buf[0] = HFinished; buf[1] = TLSFinishedLen>>16; buf[2] = TLSFinishedLen>>8; buf[3] = TLSFinishedLen; n = TLSFinishedLen+4; for(i=0; i<2; i++){ if(i==0) memmove(buf+4, "client finished", TLSFinishedLen); else memmove(buf+4, "server finished", TLSFinishedLen); if(isclient == 1-i){ if(write(hand, buf, n) != n) return -1; }else{ if(readn(hand, buf2, n) != n || memcmp(buf,buf2,n) != 0) return -1; } } return 1; } // given a plain fd and secrets established beforehand, return encrypted connection int pushtls(int fd, char *hashalg, char *encalg, int isclient, char *secret, char *dir) { char buf[8]; char dname[64]; int n, data, ctl, hand; // open a new filter; get ctl fd data = hand = -1; // /net/tls uses decimal file descriptors to name channels, hence a // user-level file server can't stand in for #a; may as well hard-code it. ctl = open("#a/tls/clone", ORDWR); if(ctl < 0) goto error; n = read(ctl, buf, sizeof(buf)-1); if(n < 0) goto error; buf[n] = 0; if(dir) sprint(dir, "#a/tls/%s", buf); // get application fd sprint(dname, "#a/tls/%s/data", buf); data = open(dname, ORDWR); if(data < 0) goto error; // get handshake fd sprint(dname, "#a/tls/%s/hand", buf); hand = open(dname, ORDWR); if(hand < 0) goto error; // speak a minimal handshake if(fprint(ctl, "fd %d 0x301", fd) < 0 || fprint(ctl, "version 0x301") < 0 || fprint(ctl, "secret %s %s %d %s", hashalg, encalg, isclient, secret) < 0 || fprint(ctl, "changecipher") < 0 || finished(hand, isclient) < 0 || fprint(ctl, "opened") < 0){ close(hand); hand = -1; goto error; } close(ctl); close(hand); close(fd); return data; error: if(data>=0) close(data); if(ctl>=0) close(ctl); if(hand>=0) close(hand); return -1; } drawterm-20170818/libc/rand.c000066400000000000000000000001171314554504700156230ustar00rootroot00000000000000#include #include int rand(void) { return lrand() & 0x7fff; } drawterm-20170818/libc/read9pmsg.c000066400000000000000000000007161314554504700165770ustar00rootroot00000000000000#include #include #include int read9pmsg(int fd, void *abuf, uint n) { int m, len; uchar *buf; buf = abuf; /* read count */ m = readn(fd, buf, BIT32SZ); if(m != BIT32SZ){ if(m < 0) return -1; return 0; } len = GBIT32(buf); if(len <= BIT32SZ || len > n){ werrstr("bad length in 9P2000 message header"); return -1; } len -= BIT32SZ; m = readn(fd, buf+BIT32SZ, len); if(m < len) return 0; return BIT32SZ+m; } drawterm-20170818/libc/readn.c000066400000000000000000000003521314554504700157710ustar00rootroot00000000000000#include #include long readn(int f, void *av, long n) { char *a; long m, t; a = av; t = 0; while(t < n){ m = read(f, a+t, n-t); if(m <= 0){ if(t == 0) return m; break; } t += m; } return t; } drawterm-20170818/libc/rune.c000066400000000000000000000054321314554504700156550ustar00rootroot00000000000000#include #include #define Bit(i) (7-(i)) /* N 0's preceded by i 1's, T(Bit(2)) is 1100 0000 */ #define T(i) (((1 << (Bit(i)+1))-1) ^ 0xFF) /* 0000 0000 0000 0111 1111 1111 */ #define RuneX(i) ((1 << (Bit(i) + ((i)-1)*Bitx))-1) enum { Bitx = Bit(1), Tx = T(1), /* 1000 0000 */ Rune1 = (1<<(Bit(0)+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */ Maskx = (1< T1 * 00080-007FF => T2 Tx * 00800-0FFFF => T3 Tx Tx * 10000-10FFFF => T4 Tx Tx Tx */ c[0] = *(uchar*)(str); if(c[0] < Tx){ *rune = c[0]; return 1; } l = c[0]; for(i = 1; i < UTFmax; i++) { c[i] = *(uchar*)(str+i); c[i] ^= Tx; if(c[i] & Testx) goto bad; l = (l << Bitx) | c[i]; if(c[0] < T(i + 2)) { l &= RuneX(i + 1); if(i == 1) { if(c[0] < T(2) || l <= Rune1) goto bad; } else if(l <= RuneX(i) || l > Runemax) goto bad; if (i == 2 && SurrogateMin <= l && l <= SurrogateMax) goto bad; *rune = l; return i + 1; } } /* * bad decoding */ bad: *rune = Bad; return 1; } int runetochar(char *str, Rune *rune) { int i, j; Rune c; c = *rune; if(c <= Rune1) { str[0] = c; return 1; } /* * one character sequence * 00000-0007F => 00-7F * two character sequence * 0080-07FF => T2 Tx * three character sequence * 0800-FFFF => T3 Tx Tx * four character sequence (21-bit value) * 10000-1FFFFF => T4 Tx Tx Tx * If the Rune is out of range or a surrogate half, * convert it to the error rune. * Do this test when i==3 because the error rune encodes to three bytes. * Doing it earlier would duplicate work, since an out of range * Rune wouldn't have fit in one or two bytes. */ for(i = 2; i < UTFmax + 1; i++){ if(i == 3){ if(c > Runemax) c = Runeerror; if(SurrogateMin <= c && c <= SurrogateMax) c = Runeerror; } if (c <= RuneX(i) || i == UTFmax ) { str[0] = T(i) | (c >> (i - 1)*Bitx); for(j = 1; j < i; j++) str[j] = Tx | ((c >> (i - j - 1)*Bitx) & Maskx); return i; } } return UTFmax; } int runelen(long c) { Rune rune; char str[10]; rune = c; return runetochar(str, &rune); } int runenlen(Rune *r, int nrune) { int nb, i; Rune c; nb = 0; while(nrune--) { c = *r++; if(c <= Rune1){ nb++; } else { for(i = 2; i < UTFmax + 1; i++) if(c <= RuneX(i) || i == UTFmax){ nb += i; break; } } } return nb; } int fullrune(char *str, int n) { int i; Rune c; if(n <= 0) return 0; c = *(uchar*)str; if(c < Tx) return 1; for(i = 3; i < UTFmax + 1; i++) if(c < T(i)) return n >= i - 1; return n >= UTFmax; } drawterm-20170818/libc/runefmtstr.c000066400000000000000000000002441314554504700171110ustar00rootroot00000000000000#include #include #include "fmtdef.h" Rune* runefmtstrflush(Fmt *f) { if(f->start == nil) return nil; *(Rune*)f->to = '\0'; return f->start; } drawterm-20170818/libc/runeseprint.c000066400000000000000000000003401314554504700172530ustar00rootroot00000000000000#include #include #include "fmtdef.h" Rune* runeseprint(Rune *buf, Rune *e, char *fmt, ...) { Rune *p; va_list args; va_start(args, fmt); p = runevseprint(buf, e, fmt, args); va_end(args); return p; } drawterm-20170818/libc/runesmprint.c000066400000000000000000000003041314554504700172630ustar00rootroot00000000000000#include #include #include "fmtdef.h" Rune* runesmprint(char *fmt, ...) { va_list args; Rune *p; va_start(args, fmt); p = runevsmprint(fmt, args); va_end(args); return p; } drawterm-20170818/libc/runesnprint.c000066400000000000000000000003371314554504700172720ustar00rootroot00000000000000#include #include #include "fmtdef.h" int runesnprint(Rune *buf, int len, char *fmt, ...) { int n; va_list args; va_start(args, fmt); n = runevsnprint(buf, len, fmt, args); va_end(args); return n; } drawterm-20170818/libc/runesprint.c000066400000000000000000000003241314554504700171100ustar00rootroot00000000000000#include #include #include "fmtdef.h" int runesprint(Rune *buf, char *fmt, ...) { int n; va_list args; va_start(args, fmt); n = runevsnprint(buf, 256, fmt, args); va_end(args); return n; } drawterm-20170818/libc/runestrcat.c000066400000000000000000000001741314554504700170740ustar00rootroot00000000000000#include #include Rune* runestrcat(Rune *s1, Rune *s2) { runestrcpy(runestrchr(s1, 0), s2); return s1; } drawterm-20170818/libc/runestrchr.c000066400000000000000000000003211314554504700170730ustar00rootroot00000000000000#include #include Rune* runestrchr(Rune *s, Rune c) { Rune c0 = c; Rune c1; if(c == 0) { while(*s++) ; return s-1; } while((c1 = *s++)) if(c1 == c0) return s-1; return 0; } drawterm-20170818/libc/runestrcmp.c000066400000000000000000000003351314554504700171030ustar00rootroot00000000000000#include #include int runestrcmp(Rune *s1, Rune *s2) { Rune c1, c2; for(;;) { c1 = *s1++; c2 = *s2++; if(c1 != c2) { if(c1 > c2) return 1; return -1; } if(c1 == 0) return 0; } } drawterm-20170818/libc/runestrcpy.c000066400000000000000000000002121314554504700171110ustar00rootroot00000000000000#include #include Rune* runestrcpy(Rune *s1, Rune *s2) { Rune *os1; os1 = s1; while(*s1++ = *s2++) ; return os1; } drawterm-20170818/libc/runestrdup.c000066400000000000000000000002641314554504700171150ustar00rootroot00000000000000#include #include Rune* runestrdup(Rune *s) { Rune *ns; ns = malloc(sizeof(Rune)*(runestrlen(s) + 1)); if(ns == 0) return 0; return runestrcpy(ns, s); } drawterm-20170818/libc/runestrecpy.c000066400000000000000000000003121314554504700172570ustar00rootroot00000000000000#include #include Rune* runestrecpy(Rune *s1, Rune *es1, Rune *s2) { if(s1 >= es1) return s1; while(*s1++ = *s2++){ if(s1 == es1){ *--s1 = '\0'; break; } } return s1; } drawterm-20170818/libc/runestrlen.c000066400000000000000000000001361314554504700171010ustar00rootroot00000000000000#include #include long runestrlen(Rune *s) { return runestrchr(s, 0) - s; } drawterm-20170818/libc/runestrncat.c000066400000000000000000000003251314554504700172500ustar00rootroot00000000000000#include #include Rune* runestrncat(Rune *s1, Rune *s2, long n) { Rune *os1; os1 = s1; s1 = runestrchr(s1, 0); while(*s1++ = *s2++) if(--n < 0) { s1[-1] = 0; break; } return os1; } drawterm-20170818/libc/runestrncmp.c000066400000000000000000000003721314554504700172620ustar00rootroot00000000000000#include #include int runestrncmp(Rune *s1, Rune *s2, long n) { Rune c1, c2; while(n > 0) { c1 = *s1++; c2 = *s2++; n--; if(c1 != c2) { if(c1 > c2) return 1; return -1; } if(c1 == 0) break; } return 0; } drawterm-20170818/libc/runestrncpy.c000066400000000000000000000003521314554504700172740ustar00rootroot00000000000000#include #include Rune* runestrncpy(Rune *s1, Rune *s2, long n) { int i; Rune *os1; os1 = s1; for(i = 0; i < n; i++) if((*s1++ = *s2++) == 0) { while(++i < n) *s1++ = 0; return os1; } return os1; } drawterm-20170818/libc/runestrrchr.c000066400000000000000000000002661314554504700172650ustar00rootroot00000000000000#include #include Rune* runestrrchr(Rune *s, Rune c) { Rune *r; if(c == 0) return runestrchr(s, 0); r = 0; while(s = runestrchr(s, c)) r = s++; return r; } drawterm-20170818/libc/runestrstr.c000066400000000000000000000006151314554504700171350ustar00rootroot00000000000000#include #include /* * Return pointer to first occurrence of s2 in s1, * 0 if none */ Rune* runestrstr(Rune *s1, Rune *s2) { Rune *p, *pa, *pb; int c0, c; c0 = *s2; if(c0 == 0) return s1; s2++; for(p=runestrchr(s1, c0); p; p=runestrchr(p+1, c0)) { pa = p; for(pb=s2;; pb++) { c = *pb; if(c == 0) return p; if(c != *++pa) break; } } return 0; } drawterm-20170818/libc/runetype.c000066400000000000000000000717271314554504700165710ustar00rootroot00000000000000#include #include /* * alpha ranges - * only covers ranges not in lower||upper */ static Rune _alpha2[] = { 0x00d8, 0x00f6, /* Ø - ö */ 0x00f8, 0x01f5, /* ø - ǵ */ 0x0250, 0x02a8, /* ɐ - ʨ */ 0x038e, 0x03a1, /* Ύ - Ρ */ 0x03a3, 0x03ce, /* Σ - ώ */ 0x03d0, 0x03d6, /* ϐ - ϖ */ 0x03e2, 0x03f3, /* Ϣ - ϳ */ 0x0490, 0x04c4, /* Ґ - ӄ */ 0x0561, 0x0587, /* ա - և */ 0x05d0, 0x05ea, /* א - ת */ 0x05f0, 0x05f2, /* װ - ײ */ 0x0621, 0x063a, /* ء - غ */ 0x0640, 0x064a, /* ـ - ي */ 0x0671, 0x06b7, /* ٱ - ڷ */ 0x06ba, 0x06be, /* ں - ھ */ 0x06c0, 0x06ce, /* ۀ - ێ */ 0x06d0, 0x06d3, /* ې - ۓ */ 0x0905, 0x0939, /* अ - ह */ 0x0958, 0x0961, /* क़ - ॡ */ 0x0985, 0x098c, /* অ - ঌ */ 0x098f, 0x0990, /* এ - ঐ */ 0x0993, 0x09a8, /* ও - ন */ 0x09aa, 0x09b0, /* প - র */ 0x09b6, 0x09b9, /* শ - হ */ 0x09dc, 0x09dd, /* ড় - ঢ় */ 0x09df, 0x09e1, /* য় - ৡ */ 0x09f0, 0x09f1, /* ৰ - ৱ */ 0x0a05, 0x0a0a, /* ਅ - ਊ */ 0x0a0f, 0x0a10, /* ਏ - ਐ */ 0x0a13, 0x0a28, /* ਓ - ਨ */ 0x0a2a, 0x0a30, /* ਪ - ਰ */ 0x0a32, 0x0a33, /* ਲ - ਲ਼ */ 0x0a35, 0x0a36, /* ਵ - ਸ਼ */ 0x0a38, 0x0a39, /* ਸ - ਹ */ 0x0a59, 0x0a5c, /* ਖ਼ - ੜ */ 0x0a85, 0x0a8b, /* અ - ઋ */ 0x0a8f, 0x0a91, /* એ - ઑ */ 0x0a93, 0x0aa8, /* ઓ - ન */ 0x0aaa, 0x0ab0, /* પ - ર */ 0x0ab2, 0x0ab3, /* લ - ળ */ 0x0ab5, 0x0ab9, /* વ - હ */ 0x0b05, 0x0b0c, /* ଅ - ଌ */ 0x0b0f, 0x0b10, /* ଏ - ଐ */ 0x0b13, 0x0b28, /* ଓ - ନ */ 0x0b2a, 0x0b30, /* ପ - ର */ 0x0b32, 0x0b33, /* ଲ - ଳ */ 0x0b36, 0x0b39, /* ଶ - ହ */ 0x0b5c, 0x0b5d, /* ଡ଼ - ଢ଼ */ 0x0b5f, 0x0b61, /* ୟ - ୡ */ 0x0b85, 0x0b8a, /* அ - ஊ */ 0x0b8e, 0x0b90, /* எ - ஐ */ 0x0b92, 0x0b95, /* ஒ - க */ 0x0b99, 0x0b9a, /* ங - ச */ 0x0b9e, 0x0b9f, /* ஞ - ட */ 0x0ba3, 0x0ba4, /* ண - த */ 0x0ba8, 0x0baa, /* ந - ப */ 0x0bae, 0x0bb5, /* ம - வ */ 0x0bb7, 0x0bb9, /* ஷ - ஹ */ 0x0c05, 0x0c0c, /* అ - ఌ */ 0x0c0e, 0x0c10, /* ఎ - ఐ */ 0x0c12, 0x0c28, /* ఒ - న */ 0x0c2a, 0x0c33, /* ప - ళ */ 0x0c35, 0x0c39, /* వ - హ */ 0x0c60, 0x0c61, /* ౠ - ౡ */ 0x0c85, 0x0c8c, /* ಅ - ಌ */ 0x0c8e, 0x0c90, /* ಎ - ಐ */ 0x0c92, 0x0ca8, /* ಒ - ನ */ 0x0caa, 0x0cb3, /* ಪ - ಳ */ 0x0cb5, 0x0cb9, /* ವ - ಹ */ 0x0ce0, 0x0ce1, /* ೠ - ೡ */ 0x0d05, 0x0d0c, /* അ - ഌ */ 0x0d0e, 0x0d10, /* എ - ഐ */ 0x0d12, 0x0d28, /* ഒ - ന */ 0x0d2a, 0x0d39, /* പ - ഹ */ 0x0d60, 0x0d61, /* ൠ - ൡ */ 0x0e01, 0x0e30, /* ก - ะ */ 0x0e32, 0x0e33, /* า - ำ */ 0x0e40, 0x0e46, /* เ - ๆ */ 0x0e5a, 0x0e5b, /* ๚ - ๛ */ 0x0e81, 0x0e82, /* ກ - ຂ */ 0x0e87, 0x0e88, /* ງ - ຈ */ 0x0e94, 0x0e97, /* ດ - ທ */ 0x0e99, 0x0e9f, /* ນ - ຟ */ 0x0ea1, 0x0ea3, /* ມ - ຣ */ 0x0eaa, 0x0eab, /* ສ - ຫ */ 0x0ead, 0x0eae, /* ອ - ຮ */ 0x0eb2, 0x0eb3, /* າ - ຳ */ 0x0ec0, 0x0ec4, /* ເ - ໄ */ 0x0edc, 0x0edd, /* ໜ - ໝ */ 0x0f18, 0x0f19, /* ༘ - ༙ */ 0x0f40, 0x0f47, /* ཀ - ཇ */ 0x0f49, 0x0f69, /* ཉ - ཀྵ */ 0x10d0, 0x10f6, /* ა - ჶ */ 0x1100, 0x1159, /* ᄀ - ᅙ */ 0x115f, 0x11a2, /* ᅟ - ᆢ */ 0x11a8, 0x11f9, /* ᆨ - ᇹ */ 0x1e00, 0x1e9b, /* Ḁ - ẛ */ 0x1f50, 0x1f57, /* ὐ - ὗ */ 0x1f80, 0x1fb4, /* ᾀ - ᾴ */ 0x1fb6, 0x1fbc, /* ᾶ - ᾼ */ 0x1fc2, 0x1fc4, /* ῂ - ῄ */ 0x1fc6, 0x1fcc, /* ῆ - ῌ */ 0x1fd0, 0x1fd3, /* ῐ - ΐ */ 0x1fd6, 0x1fdb, /* ῖ - Ί */ 0x1fe0, 0x1fec, /* ῠ - Ῥ */ 0x1ff2, 0x1ff4, /* ῲ - ῴ */ 0x1ff6, 0x1ffc, /* ῶ - ῼ */ 0x210a, 0x2113, /* ℊ - ℓ */ 0x2115, 0x211d, /* ℕ - ℝ */ 0x2120, 0x2122, /* ℠ - ™ */ 0x212a, 0x2131, /* K - ℱ */ 0x2133, 0x2138, /* ℳ - ℸ */ 0x3041, 0x3094, /* ぁ - ゔ */ 0x30a1, 0x30fa, /* ァ - ヺ */ 0x3105, 0x312c, /* ㄅ - ㄬ */ 0x3131, 0x318e, /* ㄱ - ㆎ */ 0x3192, 0x319f, /* ㆒ - ㆟ */ 0x3260, 0x327b, /* ㉠ - ㉻ */ 0x328a, 0x32b0, /* ㊊ - ㊰ */ 0x32d0, 0x32fe, /* ㋐ - ㋾ */ 0x3300, 0x3357, /* ㌀ - ㍗ */ 0x3371, 0x3376, /* ㍱ - ㍶ */ 0x337b, 0x3394, /* ㍻ - ㎔ */ 0x3399, 0x339e, /* ㎙ - ㎞ */ 0x33a9, 0x33ad, /* ㎩ - ㎭ */ 0x33b0, 0x33c1, /* ㎰ - ㏁ */ 0x33c3, 0x33c5, /* ㏃ - ㏅ */ 0x33c7, 0x33d7, /* ㏇ - ㏗ */ 0x33d9, 0x33dd, /* ㏙ - ㏝ */ 0x4e00, 0x9fff, /* 一 - 鿿 */ 0xac00, 0xd7a3, /* 가 - 힣 */ 0xf900, 0xfb06, /* 豈 - st */ 0xfb13, 0xfb17, /* ﬓ - ﬗ */ 0xfb1f, 0xfb28, /* ײַ - ﬨ */ 0xfb2a, 0xfb36, /* שׁ - זּ */ 0xfb38, 0xfb3c, /* טּ - לּ */ 0xfb40, 0xfb41, /* נּ - סּ */ 0xfb43, 0xfb44, /* ףּ - פּ */ 0xfb46, 0xfbb1, /* צּ - ﮱ */ 0xfbd3, 0xfd3d, /* ﯓ - ﴽ */ 0xfd50, 0xfd8f, /* ﵐ - ﶏ */ 0xfd92, 0xfdc7, /* ﶒ - ﷇ */ 0xfdf0, 0xfdf9, /* ﷰ - ﷹ */ 0xfe70, 0xfe72, /* ﹰ - ﹲ */ 0xfe76, 0xfefc, /* ﹶ - ﻼ */ 0xff66, 0xff6f, /* ヲ - ッ */ 0xff71, 0xff9d, /* ア - ン */ 0xffa0, 0xffbe, /* ᅠ - ᄒ */ 0xffc2, 0xffc7, /* ᅡ - ᅦ */ 0xffca, 0xffcf, /* ᅧ - ᅬ */ 0xffd2, 0xffd7, /* ᅭ - ᅲ */ 0xffda, 0xffdc, /* ᅳ - ᅵ */ }; /* * alpha singlets - * only covers ranges not in lower||upper */ static Rune _alpha1[] = { 0x00aa, /* ª */ 0x00b5, /* µ */ 0x00ba, /* º */ 0x03da, /* Ϛ */ 0x03dc, /* Ϝ */ 0x03de, /* Ϟ */ 0x03e0, /* Ϡ */ 0x06d5, /* ە */ 0x09b2, /* ল */ 0x0a5e, /* ਫ਼ */ 0x0a8d, /* ઍ */ 0x0ae0, /* ૠ */ 0x0b9c, /* ஜ */ 0x0cde, /* ೞ */ 0x0e4f, /* ๏ */ 0x0e84, /* ຄ */ 0x0e8a, /* ຊ */ 0x0e8d, /* ຍ */ 0x0ea5, /* ລ */ 0x0ea7, /* ວ */ 0x0eb0, /* ະ */ 0x0ebd, /* ຽ */ 0x1fbe, /* ι */ 0x207f, /* ⁿ */ 0x20a8, /* ₨ */ 0x2102, /* ℂ */ 0x2107, /* ℇ */ 0x2124, /* ℤ */ 0x2126, /* Ω */ 0x2128, /* ℨ */ 0xfb3e, /* מּ */ 0xfe74, /* ﹴ */ }; /* * space ranges */ static Rune _space2[] = { 0x0009, 0x000a, /* tab and newline */ 0x0020, 0x0020, /* space */ 0x00a0, 0x00a0, /*   */ 0x2000, 0x200b, /*   - ​ */ 0x2028, 0x2029, /* 
 - 
 */ 0x3000, 0x3000, /*   */ 0xfeff, 0xfeff, /*  */ }; /* * lower case ranges * 3rd col is conversion excess 500 */ static Rune _toupper2[] = { 0x0061, 0x007a, 468, /* a-z A-Z */ 0x00e0, 0x00f6, 468, /* à-ö À-Ö */ 0x00f8, 0x00fe, 468, /* ø-þ Ø-Þ */ 0x0256, 0x0257, 295, /* ɖ-ɗ Ɖ-Ɗ */ 0x0258, 0x0259, 298, /* ɘ-ə Ǝ-Ə */ 0x028a, 0x028b, 283, /* ʊ-ʋ Ʊ-Ʋ */ 0x03ad, 0x03af, 463, /* έ-ί Έ-Ί */ 0x03b1, 0x03c1, 468, /* α-ρ Α-Ρ */ 0x03c3, 0x03cb, 468, /* σ-ϋ Σ-Ϋ */ 0x03cd, 0x03ce, 437, /* ύ-ώ Ύ-Ώ */ 0x0430, 0x044f, 468, /* а-я А-Я */ 0x0451, 0x045c, 420, /* ё-ќ Ё-Ќ */ 0x045e, 0x045f, 420, /* ў-џ Ў-Џ */ 0x0561, 0x0586, 452, /* ա-ֆ Ա-Ֆ */ 0x1f00, 0x1f07, 508, /* ἀ-ἇ Ἀ-Ἇ */ 0x1f10, 0x1f15, 508, /* ἐ-ἕ Ἐ-Ἕ */ 0x1f20, 0x1f27, 508, /* ἠ-ἧ Ἠ-Ἧ */ 0x1f30, 0x1f37, 508, /* ἰ-ἷ Ἰ-Ἷ */ 0x1f40, 0x1f45, 508, /* ὀ-ὅ Ὀ-Ὅ */ 0x1f60, 0x1f67, 508, /* ὠ-ὧ Ὠ-Ὧ */ 0x1f70, 0x1f71, 574, /* ὰ-ά Ὰ-Ά */ 0x1f72, 0x1f75, 586, /* ὲ-ή Ὲ-Ή */ 0x1f76, 0x1f77, 600, /* ὶ-ί Ὶ-Ί */ 0x1f78, 0x1f79, 628, /* ὸ-ό Ὸ-Ό */ 0x1f7a, 0x1f7b, 612, /* ὺ-ύ Ὺ-Ύ */ 0x1f7c, 0x1f7d, 626, /* ὼ-ώ Ὼ-Ώ */ 0x1f80, 0x1f87, 508, /* ᾀ-ᾇ ᾈ-ᾏ */ 0x1f90, 0x1f97, 508, /* ᾐ-ᾗ ᾘ-ᾟ */ 0x1fa0, 0x1fa7, 508, /* ᾠ-ᾧ ᾨ-ᾯ */ 0x1fb0, 0x1fb1, 508, /* ᾰ-ᾱ Ᾰ-Ᾱ */ 0x1fd0, 0x1fd1, 508, /* ῐ-ῑ Ῐ-Ῑ */ 0x1fe0, 0x1fe1, 508, /* ῠ-ῡ Ῠ-Ῡ */ 0x2170, 0x217f, 484, /* ⅰ-ⅿ Ⅰ-Ⅿ */ 0x24d0, 0x24e9, 474, /* ⓐ-ⓩ Ⓐ-Ⓩ */ 0xff41, 0xff5a, 468, /* a-z A-Z */ }; /* * lower case singlets * 2nd col is conversion excess 500 */ static Rune _toupper1[] = { 0x00ff, 621, /* ÿ Ÿ */ 0x0101, 499, /* ā Ā */ 0x0103, 499, /* ă Ă */ 0x0105, 499, /* ą Ą */ 0x0107, 499, /* ć Ć */ 0x0109, 499, /* ĉ Ĉ */ 0x010b, 499, /* ċ Ċ */ 0x010d, 499, /* č Č */ 0x010f, 499, /* ď Ď */ 0x0111, 499, /* đ Đ */ 0x0113, 499, /* ē Ē */ 0x0115, 499, /* ĕ Ĕ */ 0x0117, 499, /* ė Ė */ 0x0119, 499, /* ę Ę */ 0x011b, 499, /* ě Ě */ 0x011d, 499, /* ĝ Ĝ */ 0x011f, 499, /* ğ Ğ */ 0x0121, 499, /* ġ Ġ */ 0x0123, 499, /* ģ Ģ */ 0x0125, 499, /* ĥ Ĥ */ 0x0127, 499, /* ħ Ħ */ 0x0129, 499, /* ĩ Ĩ */ 0x012b, 499, /* ī Ī */ 0x012d, 499, /* ĭ Ĭ */ 0x012f, 499, /* į Į */ 0x0131, 268, /* ı I */ 0x0133, 499, /* ij IJ */ 0x0135, 499, /* ĵ Ĵ */ 0x0137, 499, /* ķ Ķ */ 0x013a, 499, /* ĺ Ĺ */ 0x013c, 499, /* ļ Ļ */ 0x013e, 499, /* ľ Ľ */ 0x0140, 499, /* ŀ Ŀ */ 0x0142, 499, /* ł Ł */ 0x0144, 499, /* ń Ń */ 0x0146, 499, /* ņ Ņ */ 0x0148, 499, /* ň Ň */ 0x014b, 499, /* ŋ Ŋ */ 0x014d, 499, /* ō Ō */ 0x014f, 499, /* ŏ Ŏ */ 0x0151, 499, /* ő Ő */ 0x0153, 499, /* œ Œ */ 0x0155, 499, /* ŕ Ŕ */ 0x0157, 499, /* ŗ Ŗ */ 0x0159, 499, /* ř Ř */ 0x015b, 499, /* ś Ś */ 0x015d, 499, /* ŝ Ŝ */ 0x015f, 499, /* ş Ş */ 0x0161, 499, /* š Š */ 0x0163, 499, /* ţ Ţ */ 0x0165, 499, /* ť Ť */ 0x0167, 499, /* ŧ Ŧ */ 0x0169, 499, /* ũ Ũ */ 0x016b, 499, /* ū Ū */ 0x016d, 499, /* ŭ Ŭ */ 0x016f, 499, /* ů Ů */ 0x0171, 499, /* ű Ű */ 0x0173, 499, /* ų Ų */ 0x0175, 499, /* ŵ Ŵ */ 0x0177, 499, /* ŷ Ŷ */ 0x017a, 499, /* ź Ź */ 0x017c, 499, /* ż Ż */ 0x017e, 499, /* ž Ž */ 0x017f, 200, /* ſ S */ 0x0183, 499, /* ƃ Ƃ */ 0x0185, 499, /* ƅ Ƅ */ 0x0188, 499, /* ƈ Ƈ */ 0x018c, 499, /* ƌ Ƌ */ 0x0192, 499, /* ƒ Ƒ */ 0x0199, 499, /* ƙ Ƙ */ 0x01a1, 499, /* ơ Ơ */ 0x01a3, 499, /* ƣ Ƣ */ 0x01a5, 499, /* ƥ Ƥ */ 0x01a8, 499, /* ƨ Ƨ */ 0x01ad, 499, /* ƭ Ƭ */ 0x01b0, 499, /* ư Ư */ 0x01b4, 499, /* ƴ Ƴ */ 0x01b6, 499, /* ƶ Ƶ */ 0x01b9, 499, /* ƹ Ƹ */ 0x01bd, 499, /* ƽ Ƽ */ 0x01c5, 499, /* Dž DŽ */ 0x01c6, 498, /* dž DŽ */ 0x01c8, 499, /* Lj LJ */ 0x01c9, 498, /* lj LJ */ 0x01cb, 499, /* Nj NJ */ 0x01cc, 498, /* nj NJ */ 0x01ce, 499, /* ǎ Ǎ */ 0x01d0, 499, /* ǐ Ǐ */ 0x01d2, 499, /* ǒ Ǒ */ 0x01d4, 499, /* ǔ Ǔ */ 0x01d6, 499, /* ǖ Ǖ */ 0x01d8, 499, /* ǘ Ǘ */ 0x01da, 499, /* ǚ Ǚ */ 0x01dc, 499, /* ǜ Ǜ */ 0x01df, 499, /* ǟ Ǟ */ 0x01e1, 499, /* ǡ Ǡ */ 0x01e3, 499, /* ǣ Ǣ */ 0x01e5, 499, /* ǥ Ǥ */ 0x01e7, 499, /* ǧ Ǧ */ 0x01e9, 499, /* ǩ Ǩ */ 0x01eb, 499, /* ǫ Ǫ */ 0x01ed, 499, /* ǭ Ǭ */ 0x01ef, 499, /* ǯ Ǯ */ 0x01f2, 499, /* Dz DZ */ 0x01f3, 498, /* dz DZ */ 0x01f5, 499, /* ǵ Ǵ */ 0x01fb, 499, /* ǻ Ǻ */ 0x01fd, 499, /* ǽ Ǽ */ 0x01ff, 499, /* ǿ Ǿ */ 0x0201, 499, /* ȁ Ȁ */ 0x0203, 499, /* ȃ Ȃ */ 0x0205, 499, /* ȅ Ȅ */ 0x0207, 499, /* ȇ Ȇ */ 0x0209, 499, /* ȉ Ȉ */ 0x020b, 499, /* ȋ Ȋ */ 0x020d, 499, /* ȍ Ȍ */ 0x020f, 499, /* ȏ Ȏ */ 0x0211, 499, /* ȑ Ȑ */ 0x0213, 499, /* ȓ Ȓ */ 0x0215, 499, /* ȕ Ȕ */ 0x0217, 499, /* ȗ Ȗ */ 0x0253, 290, /* ɓ Ɓ */ 0x0254, 294, /* ɔ Ɔ */ 0x025b, 297, /* ɛ Ɛ */ 0x0260, 295, /* ɠ Ɠ */ 0x0263, 293, /* ɣ Ɣ */ 0x0268, 291, /* ɨ Ɨ */ 0x0269, 289, /* ɩ Ɩ */ 0x026f, 289, /* ɯ Ɯ */ 0x0272, 287, /* ɲ Ɲ */ 0x0283, 282, /* ʃ Ʃ */ 0x0288, 282, /* ʈ Ʈ */ 0x0292, 281, /* ʒ Ʒ */ 0x03ac, 462, /* ά Ά */ 0x03cc, 436, /* ό Ό */ 0x03d0, 438, /* ϐ Β */ 0x03d1, 443, /* ϑ Θ */ 0x03d5, 453, /* ϕ Φ */ 0x03d6, 446, /* ϖ Π */ 0x03e3, 499, /* ϣ Ϣ */ 0x03e5, 499, /* ϥ Ϥ */ 0x03e7, 499, /* ϧ Ϧ */ 0x03e9, 499, /* ϩ Ϩ */ 0x03eb, 499, /* ϫ Ϫ */ 0x03ed, 499, /* ϭ Ϭ */ 0x03ef, 499, /* ϯ Ϯ */ 0x03f0, 414, /* ϰ Κ */ 0x03f1, 420, /* ϱ Ρ */ 0x0461, 499, /* ѡ Ѡ */ 0x0463, 499, /* ѣ Ѣ */ 0x0465, 499, /* ѥ Ѥ */ 0x0467, 499, /* ѧ Ѧ */ 0x0469, 499, /* ѩ Ѩ */ 0x046b, 499, /* ѫ Ѫ */ 0x046d, 499, /* ѭ Ѭ */ 0x046f, 499, /* ѯ Ѯ */ 0x0471, 499, /* ѱ Ѱ */ 0x0473, 499, /* ѳ Ѳ */ 0x0475, 499, /* ѵ Ѵ */ 0x0477, 499, /* ѷ Ѷ */ 0x0479, 499, /* ѹ Ѹ */ 0x047b, 499, /* ѻ Ѻ */ 0x047d, 499, /* ѽ Ѽ */ 0x047f, 499, /* ѿ Ѿ */ 0x0481, 499, /* ҁ Ҁ */ 0x0491, 499, /* ґ Ґ */ 0x0493, 499, /* ғ Ғ */ 0x0495, 499, /* ҕ Ҕ */ 0x0497, 499, /* җ Җ */ 0x0499, 499, /* ҙ Ҙ */ 0x049b, 499, /* қ Қ */ 0x049d, 499, /* ҝ Ҝ */ 0x049f, 499, /* ҟ Ҟ */ 0x04a1, 499, /* ҡ Ҡ */ 0x04a3, 499, /* ң Ң */ 0x04a5, 499, /* ҥ Ҥ */ 0x04a7, 499, /* ҧ Ҧ */ 0x04a9, 499, /* ҩ Ҩ */ 0x04ab, 499, /* ҫ Ҫ */ 0x04ad, 499, /* ҭ Ҭ */ 0x04af, 499, /* ү Ү */ 0x04b1, 499, /* ұ Ұ */ 0x04b3, 499, /* ҳ Ҳ */ 0x04b5, 499, /* ҵ Ҵ */ 0x04b7, 499, /* ҷ Ҷ */ 0x04b9, 499, /* ҹ Ҹ */ 0x04bb, 499, /* һ Һ */ 0x04bd, 499, /* ҽ Ҽ */ 0x04bf, 499, /* ҿ Ҿ */ 0x04c2, 499, /* ӂ Ӂ */ 0x04c4, 499, /* ӄ Ӄ */ 0x04c8, 499, /* ӈ Ӈ */ 0x04cc, 499, /* ӌ Ӌ */ 0x04d1, 499, /* ӑ Ӑ */ 0x04d3, 499, /* ӓ Ӓ */ 0x04d5, 499, /* ӕ Ӕ */ 0x04d7, 499, /* ӗ Ӗ */ 0x04d9, 499, /* ә Ә */ 0x04db, 499, /* ӛ Ӛ */ 0x04dd, 499, /* ӝ Ӝ */ 0x04df, 499, /* ӟ Ӟ */ 0x04e1, 499, /* ӡ Ӡ */ 0x04e3, 499, /* ӣ Ӣ */ 0x04e5, 499, /* ӥ Ӥ */ 0x04e7, 499, /* ӧ Ӧ */ 0x04e9, 499, /* ө Ө */ 0x04eb, 499, /* ӫ Ӫ */ 0x04ef, 499, /* ӯ Ӯ */ 0x04f1, 499, /* ӱ Ӱ */ 0x04f3, 499, /* ӳ Ӳ */ 0x04f5, 499, /* ӵ Ӵ */ 0x04f9, 499, /* ӹ Ӹ */ 0x1e01, 499, /* ḁ Ḁ */ 0x1e03, 499, /* ḃ Ḃ */ 0x1e05, 499, /* ḅ Ḅ */ 0x1e07, 499, /* ḇ Ḇ */ 0x1e09, 499, /* ḉ Ḉ */ 0x1e0b, 499, /* ḋ Ḋ */ 0x1e0d, 499, /* ḍ Ḍ */ 0x1e0f, 499, /* ḏ Ḏ */ 0x1e11, 499, /* ḑ Ḑ */ 0x1e13, 499, /* ḓ Ḓ */ 0x1e15, 499, /* ḕ Ḕ */ 0x1e17, 499, /* ḗ Ḗ */ 0x1e19, 499, /* ḙ Ḙ */ 0x1e1b, 499, /* ḛ Ḛ */ 0x1e1d, 499, /* ḝ Ḝ */ 0x1e1f, 499, /* ḟ Ḟ */ 0x1e21, 499, /* ḡ Ḡ */ 0x1e23, 499, /* ḣ Ḣ */ 0x1e25, 499, /* ḥ Ḥ */ 0x1e27, 499, /* ḧ Ḧ */ 0x1e29, 499, /* ḩ Ḩ */ 0x1e2b, 499, /* ḫ Ḫ */ 0x1e2d, 499, /* ḭ Ḭ */ 0x1e2f, 499, /* ḯ Ḯ */ 0x1e31, 499, /* ḱ Ḱ */ 0x1e33, 499, /* ḳ Ḳ */ 0x1e35, 499, /* ḵ Ḵ */ 0x1e37, 499, /* ḷ Ḷ */ 0x1e39, 499, /* ḹ Ḹ */ 0x1e3b, 499, /* ḻ Ḻ */ 0x1e3d, 499, /* ḽ Ḽ */ 0x1e3f, 499, /* ḿ Ḿ */ 0x1e41, 499, /* ṁ Ṁ */ 0x1e43, 499, /* ṃ Ṃ */ 0x1e45, 499, /* ṅ Ṅ */ 0x1e47, 499, /* ṇ Ṇ */ 0x1e49, 499, /* ṉ Ṉ */ 0x1e4b, 499, /* ṋ Ṋ */ 0x1e4d, 499, /* ṍ Ṍ */ 0x1e4f, 499, /* ṏ Ṏ */ 0x1e51, 499, /* ṑ Ṑ */ 0x1e53, 499, /* ṓ Ṓ */ 0x1e55, 499, /* ṕ Ṕ */ 0x1e57, 499, /* ṗ Ṗ */ 0x1e59, 499, /* ṙ Ṙ */ 0x1e5b, 499, /* ṛ Ṛ */ 0x1e5d, 499, /* ṝ Ṝ */ 0x1e5f, 499, /* ṟ Ṟ */ 0x1e61, 499, /* ṡ Ṡ */ 0x1e63, 499, /* ṣ Ṣ */ 0x1e65, 499, /* ṥ Ṥ */ 0x1e67, 499, /* ṧ Ṧ */ 0x1e69, 499, /* ṩ Ṩ */ 0x1e6b, 499, /* ṫ Ṫ */ 0x1e6d, 499, /* ṭ Ṭ */ 0x1e6f, 499, /* ṯ Ṯ */ 0x1e71, 499, /* ṱ Ṱ */ 0x1e73, 499, /* ṳ Ṳ */ 0x1e75, 499, /* ṵ Ṵ */ 0x1e77, 499, /* ṷ Ṷ */ 0x1e79, 499, /* ṹ Ṹ */ 0x1e7b, 499, /* ṻ Ṻ */ 0x1e7d, 499, /* ṽ Ṽ */ 0x1e7f, 499, /* ṿ Ṿ */ 0x1e81, 499, /* ẁ Ẁ */ 0x1e83, 499, /* ẃ Ẃ */ 0x1e85, 499, /* ẅ Ẅ */ 0x1e87, 499, /* ẇ Ẇ */ 0x1e89, 499, /* ẉ Ẉ */ 0x1e8b, 499, /* ẋ Ẋ */ 0x1e8d, 499, /* ẍ Ẍ */ 0x1e8f, 499, /* ẏ Ẏ */ 0x1e91, 499, /* ẑ Ẑ */ 0x1e93, 499, /* ẓ Ẓ */ 0x1e95, 499, /* ẕ Ẕ */ 0x1ea1, 499, /* ạ Ạ */ 0x1ea3, 499, /* ả Ả */ 0x1ea5, 499, /* ấ Ấ */ 0x1ea7, 499, /* ầ Ầ */ 0x1ea9, 499, /* ẩ Ẩ */ 0x1eab, 499, /* ẫ Ẫ */ 0x1ead, 499, /* ậ Ậ */ 0x1eaf, 499, /* ắ Ắ */ 0x1eb1, 499, /* ằ Ằ */ 0x1eb3, 499, /* ẳ Ẳ */ 0x1eb5, 499, /* ẵ Ẵ */ 0x1eb7, 499, /* ặ Ặ */ 0x1eb9, 499, /* ẹ Ẹ */ 0x1ebb, 499, /* ẻ Ẻ */ 0x1ebd, 499, /* ẽ Ẽ */ 0x1ebf, 499, /* ế Ế */ 0x1ec1, 499, /* ề Ề */ 0x1ec3, 499, /* ể Ể */ 0x1ec5, 499, /* ễ Ễ */ 0x1ec7, 499, /* ệ Ệ */ 0x1ec9, 499, /* ỉ Ỉ */ 0x1ecb, 499, /* ị Ị */ 0x1ecd, 499, /* ọ Ọ */ 0x1ecf, 499, /* ỏ Ỏ */ 0x1ed1, 499, /* ố Ố */ 0x1ed3, 499, /* ồ Ồ */ 0x1ed5, 499, /* ổ Ổ */ 0x1ed7, 499, /* ỗ Ỗ */ 0x1ed9, 499, /* ộ Ộ */ 0x1edb, 499, /* ớ Ớ */ 0x1edd, 499, /* ờ Ờ */ 0x1edf, 499, /* ở Ở */ 0x1ee1, 499, /* ỡ Ỡ */ 0x1ee3, 499, /* ợ Ợ */ 0x1ee5, 499, /* ụ Ụ */ 0x1ee7, 499, /* ủ Ủ */ 0x1ee9, 499, /* ứ Ứ */ 0x1eeb, 499, /* ừ Ừ */ 0x1eed, 499, /* ử Ử */ 0x1eef, 499, /* ữ Ữ */ 0x1ef1, 499, /* ự Ự */ 0x1ef3, 499, /* ỳ Ỳ */ 0x1ef5, 499, /* ỵ Ỵ */ 0x1ef7, 499, /* ỷ Ỷ */ 0x1ef9, 499, /* ỹ Ỹ */ 0x1f51, 508, /* ὑ Ὑ */ 0x1f53, 508, /* ὓ Ὓ */ 0x1f55, 508, /* ὕ Ὕ */ 0x1f57, 508, /* ὗ Ὗ */ 0x1fb3, 509, /* ᾳ ᾼ */ 0x1fc3, 509, /* ῃ ῌ */ 0x1fe5, 507, /* ῥ Ῥ */ 0x1ff3, 509, /* ῳ ῼ */ }; /* * upper case ranges * 3rd col is conversion excess 500 */ static Rune _tolower2[] = { 0x0041, 0x005a, 532, /* A-Z a-z */ 0x00c0, 0x00d6, 532, /* À-Ö à-ö */ 0x00d8, 0x00de, 532, /* Ø-Þ ø-þ */ 0x0189, 0x018a, 705, /* Ɖ-Ɗ ɖ-ɗ */ 0x018e, 0x018f, 702, /* Ǝ-Ə ɘ-ə */ 0x01b1, 0x01b2, 717, /* Ʊ-Ʋ ʊ-ʋ */ 0x0388, 0x038a, 537, /* Έ-Ί έ-ί */ 0x038e, 0x038f, 563, /* Ύ-Ώ ύ-ώ */ 0x0391, 0x03a1, 532, /* Α-Ρ α-ρ */ 0x03a3, 0x03ab, 532, /* Σ-Ϋ σ-ϋ */ 0x0401, 0x040c, 580, /* Ё-Ќ ё-ќ */ 0x040e, 0x040f, 580, /* Ў-Џ ў-џ */ 0x0410, 0x042f, 532, /* А-Я а-я */ 0x0531, 0x0556, 548, /* Ա-Ֆ ա-ֆ */ 0x10a0, 0x10c5, 548, /* Ⴀ-Ⴥ ა-ჵ */ 0x1f08, 0x1f0f, 492, /* Ἀ-Ἇ ἀ-ἇ */ 0x1f18, 0x1f1d, 492, /* Ἐ-Ἕ ἐ-ἕ */ 0x1f28, 0x1f2f, 492, /* Ἠ-Ἧ ἠ-ἧ */ 0x1f38, 0x1f3f, 492, /* Ἰ-Ἷ ἰ-ἷ */ 0x1f48, 0x1f4d, 492, /* Ὀ-Ὅ ὀ-ὅ */ 0x1f68, 0x1f6f, 492, /* Ὠ-Ὧ ὠ-ὧ */ 0x1f88, 0x1f8f, 492, /* ᾈ-ᾏ ᾀ-ᾇ */ 0x1f98, 0x1f9f, 492, /* ᾘ-ᾟ ᾐ-ᾗ */ 0x1fa8, 0x1faf, 492, /* ᾨ-ᾯ ᾠ-ᾧ */ 0x1fb8, 0x1fb9, 492, /* Ᾰ-Ᾱ ᾰ-ᾱ */ 0x1fba, 0x1fbb, 426, /* Ὰ-Ά ὰ-ά */ 0x1fc8, 0x1fcb, 414, /* Ὲ-Ή ὲ-ή */ 0x1fd8, 0x1fd9, 492, /* Ῐ-Ῑ ῐ-ῑ */ 0x1fda, 0x1fdb, 400, /* Ὶ-Ί ὶ-ί */ 0x1fe8, 0x1fe9, 492, /* Ῠ-Ῡ ῠ-ῡ */ 0x1fea, 0x1feb, 388, /* Ὺ-Ύ ὺ-ύ */ 0x1ff8, 0x1ff9, 372, /* Ὸ-Ό ὸ-ό */ 0x1ffa, 0x1ffb, 374, /* Ὼ-Ώ ὼ-ώ */ 0x2160, 0x216f, 516, /* Ⅰ-Ⅿ ⅰ-ⅿ */ 0x24b6, 0x24cf, 526, /* Ⓐ-Ⓩ ⓐ-ⓩ */ 0xff21, 0xff3a, 532, /* A-Z a-z */ }; /* * upper case singlets * 2nd col is conversion excess 500 */ static Rune _tolower1[] = { 0x0100, 501, /* Ā ā */ 0x0102, 501, /* Ă ă */ 0x0104, 501, /* Ą ą */ 0x0106, 501, /* Ć ć */ 0x0108, 501, /* Ĉ ĉ */ 0x010a, 501, /* Ċ ċ */ 0x010c, 501, /* Č č */ 0x010e, 501, /* Ď ď */ 0x0110, 501, /* Đ đ */ 0x0112, 501, /* Ē ē */ 0x0114, 501, /* Ĕ ĕ */ 0x0116, 501, /* Ė ė */ 0x0118, 501, /* Ę ę */ 0x011a, 501, /* Ě ě */ 0x011c, 501, /* Ĝ ĝ */ 0x011e, 501, /* Ğ ğ */ 0x0120, 501, /* Ġ ġ */ 0x0122, 501, /* Ģ ģ */ 0x0124, 501, /* Ĥ ĥ */ 0x0126, 501, /* Ħ ħ */ 0x0128, 501, /* Ĩ ĩ */ 0x012a, 501, /* Ī ī */ 0x012c, 501, /* Ĭ ĭ */ 0x012e, 501, /* Į į */ 0x0130, 301, /* İ i */ 0x0132, 501, /* IJ ij */ 0x0134, 501, /* Ĵ ĵ */ 0x0136, 501, /* Ķ ķ */ 0x0139, 501, /* Ĺ ĺ */ 0x013b, 501, /* Ļ ļ */ 0x013d, 501, /* Ľ ľ */ 0x013f, 501, /* Ŀ ŀ */ 0x0141, 501, /* Ł ł */ 0x0143, 501, /* Ń ń */ 0x0145, 501, /* Ņ ņ */ 0x0147, 501, /* Ň ň */ 0x014a, 501, /* Ŋ ŋ */ 0x014c, 501, /* Ō ō */ 0x014e, 501, /* Ŏ ŏ */ 0x0150, 501, /* Ő ő */ 0x0152, 501, /* Œ œ */ 0x0154, 501, /* Ŕ ŕ */ 0x0156, 501, /* Ŗ ŗ */ 0x0158, 501, /* Ř ř */ 0x015a, 501, /* Ś ś */ 0x015c, 501, /* Ŝ ŝ */ 0x015e, 501, /* Ş ş */ 0x0160, 501, /* Š š */ 0x0162, 501, /* Ţ ţ */ 0x0164, 501, /* Ť ť */ 0x0166, 501, /* Ŧ ŧ */ 0x0168, 501, /* Ũ ũ */ 0x016a, 501, /* Ū ū */ 0x016c, 501, /* Ŭ ŭ */ 0x016e, 501, /* Ů ů */ 0x0170, 501, /* Ű ű */ 0x0172, 501, /* Ų ų */ 0x0174, 501, /* Ŵ ŵ */ 0x0176, 501, /* Ŷ ŷ */ 0x0178, 379, /* Ÿ ÿ */ 0x0179, 501, /* Ź ź */ 0x017b, 501, /* Ż ż */ 0x017d, 501, /* Ž ž */ 0x0181, 710, /* Ɓ ɓ */ 0x0182, 501, /* Ƃ ƃ */ 0x0184, 501, /* Ƅ ƅ */ 0x0186, 706, /* Ɔ ɔ */ 0x0187, 501, /* Ƈ ƈ */ 0x018b, 501, /* Ƌ ƌ */ 0x0190, 703, /* Ɛ ɛ */ 0x0191, 501, /* Ƒ ƒ */ 0x0193, 705, /* Ɠ ɠ */ 0x0194, 707, /* Ɣ ɣ */ 0x0196, 711, /* Ɩ ɩ */ 0x0197, 709, /* Ɨ ɨ */ 0x0198, 501, /* Ƙ ƙ */ 0x019c, 711, /* Ɯ ɯ */ 0x019d, 713, /* Ɲ ɲ */ 0x01a0, 501, /* Ơ ơ */ 0x01a2, 501, /* Ƣ ƣ */ 0x01a4, 501, /* Ƥ ƥ */ 0x01a7, 501, /* Ƨ ƨ */ 0x01a9, 718, /* Ʃ ʃ */ 0x01ac, 501, /* Ƭ ƭ */ 0x01ae, 718, /* Ʈ ʈ */ 0x01af, 501, /* Ư ư */ 0x01b3, 501, /* Ƴ ƴ */ 0x01b5, 501, /* Ƶ ƶ */ 0x01b7, 719, /* Ʒ ʒ */ 0x01b8, 501, /* Ƹ ƹ */ 0x01bc, 501, /* Ƽ ƽ */ 0x01c4, 502, /* DŽ dž */ 0x01c5, 501, /* Dž dž */ 0x01c7, 502, /* LJ lj */ 0x01c8, 501, /* Lj lj */ 0x01ca, 502, /* NJ nj */ 0x01cb, 501, /* Nj nj */ 0x01cd, 501, /* Ǎ ǎ */ 0x01cf, 501, /* Ǐ ǐ */ 0x01d1, 501, /* Ǒ ǒ */ 0x01d3, 501, /* Ǔ ǔ */ 0x01d5, 501, /* Ǖ ǖ */ 0x01d7, 501, /* Ǘ ǘ */ 0x01d9, 501, /* Ǚ ǚ */ 0x01db, 501, /* Ǜ ǜ */ 0x01de, 501, /* Ǟ ǟ */ 0x01e0, 501, /* Ǡ ǡ */ 0x01e2, 501, /* Ǣ ǣ */ 0x01e4, 501, /* Ǥ ǥ */ 0x01e6, 501, /* Ǧ ǧ */ 0x01e8, 501, /* Ǩ ǩ */ 0x01ea, 501, /* Ǫ ǫ */ 0x01ec, 501, /* Ǭ ǭ */ 0x01ee, 501, /* Ǯ ǯ */ 0x01f1, 502, /* DZ dz */ 0x01f2, 501, /* Dz dz */ 0x01f4, 501, /* Ǵ ǵ */ 0x01fa, 501, /* Ǻ ǻ */ 0x01fc, 501, /* Ǽ ǽ */ 0x01fe, 501, /* Ǿ ǿ */ 0x0200, 501, /* Ȁ ȁ */ 0x0202, 501, /* Ȃ ȃ */ 0x0204, 501, /* Ȅ ȅ */ 0x0206, 501, /* Ȇ ȇ */ 0x0208, 501, /* Ȉ ȉ */ 0x020a, 501, /* Ȋ ȋ */ 0x020c, 501, /* Ȍ ȍ */ 0x020e, 501, /* Ȏ ȏ */ 0x0210, 501, /* Ȑ ȑ */ 0x0212, 501, /* Ȓ ȓ */ 0x0214, 501, /* Ȕ ȕ */ 0x0216, 501, /* Ȗ ȗ */ 0x0386, 538, /* Ά ά */ 0x038c, 564, /* Ό ό */ 0x03e2, 501, /* Ϣ ϣ */ 0x03e4, 501, /* Ϥ ϥ */ 0x03e6, 501, /* Ϧ ϧ */ 0x03e8, 501, /* Ϩ ϩ */ 0x03ea, 501, /* Ϫ ϫ */ 0x03ec, 501, /* Ϭ ϭ */ 0x03ee, 501, /* Ϯ ϯ */ 0x0460, 501, /* Ѡ ѡ */ 0x0462, 501, /* Ѣ ѣ */ 0x0464, 501, /* Ѥ ѥ */ 0x0466, 501, /* Ѧ ѧ */ 0x0468, 501, /* Ѩ ѩ */ 0x046a, 501, /* Ѫ ѫ */ 0x046c, 501, /* Ѭ ѭ */ 0x046e, 501, /* Ѯ ѯ */ 0x0470, 501, /* Ѱ ѱ */ 0x0472, 501, /* Ѳ ѳ */ 0x0474, 501, /* Ѵ ѵ */ 0x0476, 501, /* Ѷ ѷ */ 0x0478, 501, /* Ѹ ѹ */ 0x047a, 501, /* Ѻ ѻ */ 0x047c, 501, /* Ѽ ѽ */ 0x047e, 501, /* Ѿ ѿ */ 0x0480, 501, /* Ҁ ҁ */ 0x0490, 501, /* Ґ ґ */ 0x0492, 501, /* Ғ ғ */ 0x0494, 501, /* Ҕ ҕ */ 0x0496, 501, /* Җ җ */ 0x0498, 501, /* Ҙ ҙ */ 0x049a, 501, /* Қ қ */ 0x049c, 501, /* Ҝ ҝ */ 0x049e, 501, /* Ҟ ҟ */ 0x04a0, 501, /* Ҡ ҡ */ 0x04a2, 501, /* Ң ң */ 0x04a4, 501, /* Ҥ ҥ */ 0x04a6, 501, /* Ҧ ҧ */ 0x04a8, 501, /* Ҩ ҩ */ 0x04aa, 501, /* Ҫ ҫ */ 0x04ac, 501, /* Ҭ ҭ */ 0x04ae, 501, /* Ү ү */ 0x04b0, 501, /* Ұ ұ */ 0x04b2, 501, /* Ҳ ҳ */ 0x04b4, 501, /* Ҵ ҵ */ 0x04b6, 501, /* Ҷ ҷ */ 0x04b8, 501, /* Ҹ ҹ */ 0x04ba, 501, /* Һ һ */ 0x04bc, 501, /* Ҽ ҽ */ 0x04be, 501, /* Ҿ ҿ */ 0x04c1, 501, /* Ӂ ӂ */ 0x04c3, 501, /* Ӄ ӄ */ 0x04c7, 501, /* Ӈ ӈ */ 0x04cb, 501, /* Ӌ ӌ */ 0x04d0, 501, /* Ӑ ӑ */ 0x04d2, 501, /* Ӓ ӓ */ 0x04d4, 501, /* Ӕ ӕ */ 0x04d6, 501, /* Ӗ ӗ */ 0x04d8, 501, /* Ә ә */ 0x04da, 501, /* Ӛ ӛ */ 0x04dc, 501, /* Ӝ ӝ */ 0x04de, 501, /* Ӟ ӟ */ 0x04e0, 501, /* Ӡ ӡ */ 0x04e2, 501, /* Ӣ ӣ */ 0x04e4, 501, /* Ӥ ӥ */ 0x04e6, 501, /* Ӧ ӧ */ 0x04e8, 501, /* Ө ө */ 0x04ea, 501, /* Ӫ ӫ */ 0x04ee, 501, /* Ӯ ӯ */ 0x04f0, 501, /* Ӱ ӱ */ 0x04f2, 501, /* Ӳ ӳ */ 0x04f4, 501, /* Ӵ ӵ */ 0x04f8, 501, /* Ӹ ӹ */ 0x1e00, 501, /* Ḁ ḁ */ 0x1e02, 501, /* Ḃ ḃ */ 0x1e04, 501, /* Ḅ ḅ */ 0x1e06, 501, /* Ḇ ḇ */ 0x1e08, 501, /* Ḉ ḉ */ 0x1e0a, 501, /* Ḋ ḋ */ 0x1e0c, 501, /* Ḍ ḍ */ 0x1e0e, 501, /* Ḏ ḏ */ 0x1e10, 501, /* Ḑ ḑ */ 0x1e12, 501, /* Ḓ ḓ */ 0x1e14, 501, /* Ḕ ḕ */ 0x1e16, 501, /* Ḗ ḗ */ 0x1e18, 501, /* Ḙ ḙ */ 0x1e1a, 501, /* Ḛ ḛ */ 0x1e1c, 501, /* Ḝ ḝ */ 0x1e1e, 501, /* Ḟ ḟ */ 0x1e20, 501, /* Ḡ ḡ */ 0x1e22, 501, /* Ḣ ḣ */ 0x1e24, 501, /* Ḥ ḥ */ 0x1e26, 501, /* Ḧ ḧ */ 0x1e28, 501, /* Ḩ ḩ */ 0x1e2a, 501, /* Ḫ ḫ */ 0x1e2c, 501, /* Ḭ ḭ */ 0x1e2e, 501, /* Ḯ ḯ */ 0x1e30, 501, /* Ḱ ḱ */ 0x1e32, 501, /* Ḳ ḳ */ 0x1e34, 501, /* Ḵ ḵ */ 0x1e36, 501, /* Ḷ ḷ */ 0x1e38, 501, /* Ḹ ḹ */ 0x1e3a, 501, /* Ḻ ḻ */ 0x1e3c, 501, /* Ḽ ḽ */ 0x1e3e, 501, /* Ḿ ḿ */ 0x1e40, 501, /* Ṁ ṁ */ 0x1e42, 501, /* Ṃ ṃ */ 0x1e44, 501, /* Ṅ ṅ */ 0x1e46, 501, /* Ṇ ṇ */ 0x1e48, 501, /* Ṉ ṉ */ 0x1e4a, 501, /* Ṋ ṋ */ 0x1e4c, 501, /* Ṍ ṍ */ 0x1e4e, 501, /* Ṏ ṏ */ 0x1e50, 501, /* Ṑ ṑ */ 0x1e52, 501, /* Ṓ ṓ */ 0x1e54, 501, /* Ṕ ṕ */ 0x1e56, 501, /* Ṗ ṗ */ 0x1e58, 501, /* Ṙ ṙ */ 0x1e5a, 501, /* Ṛ ṛ */ 0x1e5c, 501, /* Ṝ ṝ */ 0x1e5e, 501, /* Ṟ ṟ */ 0x1e60, 501, /* Ṡ ṡ */ 0x1e62, 501, /* Ṣ ṣ */ 0x1e64, 501, /* Ṥ ṥ */ 0x1e66, 501, /* Ṧ ṧ */ 0x1e68, 501, /* Ṩ ṩ */ 0x1e6a, 501, /* Ṫ ṫ */ 0x1e6c, 501, /* Ṭ ṭ */ 0x1e6e, 501, /* Ṯ ṯ */ 0x1e70, 501, /* Ṱ ṱ */ 0x1e72, 501, /* Ṳ ṳ */ 0x1e74, 501, /* Ṵ ṵ */ 0x1e76, 501, /* Ṷ ṷ */ 0x1e78, 501, /* Ṹ ṹ */ 0x1e7a, 501, /* Ṻ ṻ */ 0x1e7c, 501, /* Ṽ ṽ */ 0x1e7e, 501, /* Ṿ ṿ */ 0x1e80, 501, /* Ẁ ẁ */ 0x1e82, 501, /* Ẃ ẃ */ 0x1e84, 501, /* Ẅ ẅ */ 0x1e86, 501, /* Ẇ ẇ */ 0x1e88, 501, /* Ẉ ẉ */ 0x1e8a, 501, /* Ẋ ẋ */ 0x1e8c, 501, /* Ẍ ẍ */ 0x1e8e, 501, /* Ẏ ẏ */ 0x1e90, 501, /* Ẑ ẑ */ 0x1e92, 501, /* Ẓ ẓ */ 0x1e94, 501, /* Ẕ ẕ */ 0x1ea0, 501, /* Ạ ạ */ 0x1ea2, 501, /* Ả ả */ 0x1ea4, 501, /* Ấ ấ */ 0x1ea6, 501, /* Ầ ầ */ 0x1ea8, 501, /* Ẩ ẩ */ 0x1eaa, 501, /* Ẫ ẫ */ 0x1eac, 501, /* Ậ ậ */ 0x1eae, 501, /* Ắ ắ */ 0x1eb0, 501, /* Ằ ằ */ 0x1eb2, 501, /* Ẳ ẳ */ 0x1eb4, 501, /* Ẵ ẵ */ 0x1eb6, 501, /* Ặ ặ */ 0x1eb8, 501, /* Ẹ ẹ */ 0x1eba, 501, /* Ẻ ẻ */ 0x1ebc, 501, /* Ẽ ẽ */ 0x1ebe, 501, /* Ế ế */ 0x1ec0, 501, /* Ề ề */ 0x1ec2, 501, /* Ể ể */ 0x1ec4, 501, /* Ễ ễ */ 0x1ec6, 501, /* Ệ ệ */ 0x1ec8, 501, /* Ỉ ỉ */ 0x1eca, 501, /* Ị ị */ 0x1ecc, 501, /* Ọ ọ */ 0x1ece, 501, /* Ỏ ỏ */ 0x1ed0, 501, /* Ố ố */ 0x1ed2, 501, /* Ồ ồ */ 0x1ed4, 501, /* Ổ ổ */ 0x1ed6, 501, /* Ỗ ỗ */ 0x1ed8, 501, /* Ộ ộ */ 0x1eda, 501, /* Ớ ớ */ 0x1edc, 501, /* Ờ ờ */ 0x1ede, 501, /* Ở ở */ 0x1ee0, 501, /* Ỡ ỡ */ 0x1ee2, 501, /* Ợ ợ */ 0x1ee4, 501, /* Ụ ụ */ 0x1ee6, 501, /* Ủ ủ */ 0x1ee8, 501, /* Ứ ứ */ 0x1eea, 501, /* Ừ ừ */ 0x1eec, 501, /* Ử ử */ 0x1eee, 501, /* Ữ ữ */ 0x1ef0, 501, /* Ự ự */ 0x1ef2, 501, /* Ỳ ỳ */ 0x1ef4, 501, /* Ỵ ỵ */ 0x1ef6, 501, /* Ỷ ỷ */ 0x1ef8, 501, /* Ỹ ỹ */ 0x1f59, 492, /* Ὑ ὑ */ 0x1f5b, 492, /* Ὓ ὓ */ 0x1f5d, 492, /* Ὕ ὕ */ 0x1f5f, 492, /* Ὗ ὗ */ 0x1fbc, 491, /* ᾼ ᾳ */ 0x1fcc, 491, /* ῌ ῃ */ 0x1fec, 493, /* Ῥ ῥ */ 0x1ffc, 491, /* ῼ ῳ */ }; /* * title characters are those between * upper and lower case. ie DZ Dz dz */ static Rune _totitle1[] = { 0x01c4, 501, /* DŽ Dž */ 0x01c6, 499, /* dž Dž */ 0x01c7, 501, /* LJ Lj */ 0x01c9, 499, /* lj Lj */ 0x01ca, 501, /* NJ Nj */ 0x01cc, 499, /* nj Nj */ 0x01f1, 501, /* DZ Dz */ 0x01f3, 499, /* dz Dz */ }; #define bsearch xbsearch static Rune* bsearch(Rune c, Rune *t, int n, int ne) { Rune *p; int m; while(n > 1) { m = n/2; p = t + m*ne; if(c >= p[0]) { t = p; n = n-m; } else n = m; } if(n && c >= t[0]) return t; return 0; } Rune tolowerrune(Rune c) { Rune *p; p = bsearch(c, _tolower2, nelem(_tolower2)/3, 3); if(p && c >= p[0] && c <= p[1]) return c + p[2] - 500; p = bsearch(c, _tolower1, nelem(_tolower1)/2, 2); if(p && c == p[0]) return c + p[1] - 500; return c; } Rune toupperrune(Rune c) { Rune *p; p = bsearch(c, _toupper2, nelem(_toupper2)/3, 3); if(p && c >= p[0] && c <= p[1]) return c + p[2] - 500; p = bsearch(c, _toupper1, nelem(_toupper1)/2, 2); if(p && c == p[0]) return c + p[1] - 500; return c; } Rune totitlerune(Rune c) { Rune *p; p = bsearch(c, _totitle1, nelem(_totitle1)/2, 2); if(p && c == p[0]) return c + p[1] - 500; return c; } int islowerrune(Rune c) { Rune *p; p = bsearch(c, _toupper2, nelem(_toupper2)/3, 3); if(p && c >= p[0] && c <= p[1]) return 1; p = bsearch(c, _toupper1, nelem(_toupper1)/2, 2); if(p && c == p[0]) return 1; return 0; } int isupperrune(Rune c) { Rune *p; p = bsearch(c, _tolower2, nelem(_tolower2)/3, 3); if(p && c >= p[0] && c <= p[1]) return 1; p = bsearch(c, _tolower1, nelem(_tolower1)/2, 2); if(p && c == p[0]) return 1; return 0; } int isalpharune(Rune c) { Rune *p; if(isupperrune(c) || islowerrune(c)) return 1; p = bsearch(c, _alpha2, nelem(_alpha2)/2, 2); if(p && c >= p[0] && c <= p[1]) return 1; p = bsearch(c, _alpha1, nelem(_alpha1), 1); if(p && c == p[0]) return 1; return 0; } int istitlerune(Rune c) { return isupperrune(c) && islowerrune(c); } int isspacerune(Rune c) { Rune *p; p = bsearch(c, _space2, nelem(_space2)/2, 2); if(p && c >= p[0] && c <= p[1]) return 1; return 0; } drawterm-20170818/libc/runevseprint.c000066400000000000000000000005521314554504700174460ustar00rootroot00000000000000#include #include #include "fmtdef.h" Rune* runevseprint(Rune *buf, Rune *e, char *fmt, va_list args) { Fmt f; if(e <= buf) return nil; f.runes = 1; f.start = buf; f.to = buf; f.stop = e - 1; f.flush = 0; f.farg = nil; f.nfmt = 0; VA_COPY(f.args,args); dofmt(&f, fmt); VA_END(f.args); *(Rune*)f.to = '\0'; return (Rune*)f.to; } drawterm-20170818/libc/runevsmprint.c000066400000000000000000000021171314554504700174550ustar00rootroot00000000000000#include #include #include "fmtdef.h" static int runeFmtStrFlush(Fmt *f) { Rune *s; int n; if(f->start == nil) return 0; n = (uintptr)f->farg; n *= 2; s = (Rune*)f->start; f->start = realloc(s, sizeof(Rune)*n); if(f->start == nil){ f->farg = nil; f->to = nil; f->stop = nil; free(s); return 0; } f->farg = (void*)(uintptr)n; f->to = (Rune*)f->start + ((Rune*)f->to - s); f->stop = (Rune*)f->start + n - 1; return 1; } int runefmtstrinit(Fmt *f) { int n; memset(f, 0, sizeof *f); f->runes = 1; n = 32; f->start = malloc(sizeof(Rune)*n); if(f->start == nil) return -1; f->to = f->start; f->stop = (Rune*)f->start + n - 1; f->flush = runeFmtStrFlush; f->farg = (void*)(uintptr)n; f->nfmt = 0; return 0; } /* * print into an allocated string buffer */ Rune* runevsmprint(char *fmt, va_list args) { Fmt f; int n; if(runefmtstrinit(&f) < 0) return nil; VA_COPY(f.args,args); n = dofmt(&f, fmt); VA_END(f.args); if(f.start == nil) return nil; if(n < 0){ free(f.start); return nil; } *(Rune*)f.to = '\0'; return (Rune*)f.start; } drawterm-20170818/libc/runevsnprint.c000066400000000000000000000005641314554504700174620ustar00rootroot00000000000000#include #include #include "fmtdef.h" int runevsnprint(Rune *buf, int len, char *fmt, va_list args) { Fmt f; if(len <= 0) return -1; f.runes = 1; f.start = buf; f.to = buf; f.stop = buf + len - 1; f.flush = 0; f.farg = nil; f.nfmt = 0; VA_COPY(f.args,args); dofmt(&f, fmt); VA_END(f.args); *(Rune*)f.to = '\0'; return (Rune*)f.to - buf; } drawterm-20170818/libc/seprint.c000066400000000000000000000003301314554504700163600ustar00rootroot00000000000000#include #include #include "fmtdef.h" char* seprint(char *buf, char *e, char *fmt, ...) { char *p; va_list args; va_start(args, fmt); p = vseprint(buf, e, fmt, args); va_end(args); return p; } drawterm-20170818/libc/smprint.c000066400000000000000000000002741314554504700163770ustar00rootroot00000000000000#include #include #include "fmtdef.h" char* smprint(char *fmt, ...) { va_list args; char *p; va_start(args, fmt); p = vsmprint(fmt, args); va_end(args); return p; } drawterm-20170818/libc/snprint.c000066400000000000000000000003271314554504700163770ustar00rootroot00000000000000#include #include #include "fmtdef.h" int snprint(char *buf, int len, char *fmt, ...) { int n; va_list args; va_start(args, fmt); n = vsnprint(buf, len, fmt, args); va_end(args); return n; } drawterm-20170818/libc/sprint.c000066400000000000000000000007161314554504700162230ustar00rootroot00000000000000#include #include #include "fmtdef.h" int sprint(char *buf, char *fmt, ...) { int n; uint len; va_list args; len = 1<<30; /* big number, but sprint is deprecated anyway */ /* * on PowerPC, the stack is near the top of memory, so * we must be sure not to overflow a 32-bit pointer. */ if((uintptr)buf+len < (uintptr)buf) len = -(uintptr)buf-1; va_start(args, fmt); n = vsnprint(buf, len, fmt, args); va_end(args); return n; } drawterm-20170818/libc/strecpy.c000066400000000000000000000003371314554504700163740ustar00rootroot00000000000000#include #include char* strecpy(char *to, char *e, char *from) { if(to >= e) return to; to = memccpy(to, from, '\0', e - to); if(to == nil){ to = e - 1; *to = '\0'; }else{ to--; } return to; } drawterm-20170818/libc/strtod.c000066400000000000000000000203311314554504700162160ustar00rootroot00000000000000#include #include #include "fmtdef.h" static ulong umuldiv(ulong a, ulong b, ulong c) { double d; d = ((double)a * (double)b) / (double)c; if(d >= 4294967295.) d = 4294967295.; return (ulong)d; } /* * This routine will convert to arbitrary precision * floating point entirely in multi-precision fixed. * The answer is the closest floating point number to * the given decimal number. Exactly half way are * rounded ala ieee rules. * Method is to scale input decimal between .500 and .999... * with external power of 2, then binary search for the * closest mantissa to this decimal number. * Nmant is is the required precision. (53 for ieee dp) * Nbits is the max number of bits/word. (must be <= 28) * Prec is calculated - the number of words of fixed mantissa. */ enum { Nbits = 28, /* bits safely represented in a ulong */ Nmant = 53, /* bits of precision required */ Prec = (Nmant+Nbits+1)/Nbits, /* words of Nbits each to represent mantissa */ Sigbit = 1<<(Prec*Nbits-Nmant), /* first significant bit of Prec-th word */ Ndig = 1500, One = (ulong)(1<>1), Maxe = 310, Fsign = 1<<0, /* found - */ Fesign = 1<<1, /* found e- */ Fdpoint = 1<<2, /* found . */ S0 = 0, /* _ _S0 +S1 #S2 .S3 */ S1, /* _+ #S2 .S3 */ S2, /* _+# #S2 .S4 eS5 */ S3, /* _+. #S4 */ S4, /* _+#.# #S4 eS5 */ S5, /* _+#.#e +S6 #S7 */ S6, /* _+#.#e+ #S7 */ S7, /* _+#.#e+# #S7 */ }; static int xcmp(char*, char*); static int fpcmp(char*, ulong*); static void frnorm(ulong*); static void divascii(char*, int*, int*, int*); static void mulascii(char*, int*, int*, int*); typedef struct Tab Tab; struct Tab { int bp; int siz; char* cmp; }; #ifndef ERANGE #define ERANGE 12345 #endif double fmtstrtod(const char *as, char **aas) { int na, ex, dp, bp, c, i, flag, state; ulong low[Prec], hig[Prec], mid[Prec]; double d; char *s, a[Ndig]; flag = 0; /* Fsign, Fesign, Fdpoint */ na = 0; /* number of digits of a[] */ dp = 0; /* na of decimal point */ ex = 0; /* exonent */ state = S0; for(s=(char*)as;; s++) { c = *s; if(c >= '0' && c <= '9') { switch(state) { case S0: case S1: case S2: state = S2; break; case S3: case S4: state = S4; break; case S5: case S6: case S7: state = S7; ex = ex*10 + (c-'0'); continue; } if(na == 0 && c == '0') { dp--; continue; } if(na < Ndig-50) a[na++] = c; continue; } switch(c) { case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': if(state == S0) continue; break; case '-': if(state == S0) flag |= Fsign; else flag |= Fesign; case '+': if(state == S0) state = S1; else if(state == S5) state = S6; else break; /* syntax */ continue; case '.': flag |= Fdpoint; dp = na; if(state == S0 || state == S1) { state = S3; continue; } if(state == S2) { state = S4; continue; } break; case 'e': case 'E': if(state == S2 || state == S4) { state = S5; continue; } break; } break; } /* * clean up return char-pointer */ switch(state) { case S0: if(xcmp(s, "nan") == 0) { if(aas != nil) *aas = s+3; goto retnan; } case S1: if(xcmp(s, "infinity") == 0) { if(aas != nil) *aas = s+8; goto retinf; } if(xcmp(s, "inf") == 0) { if(aas != nil) *aas = s+3; goto retinf; } case S3: if(aas != nil) *aas = (char*)as; goto ret0; /* no digits found */ case S6: s--; /* back over +- */ case S5: s--; /* back over e */ break; } if(aas != nil) *aas = s; if(flag & Fdpoint) while(na > 0 && a[na-1] == '0') na--; if(na == 0) goto ret0; /* zero */ a[na] = 0; if(!(flag & Fdpoint)) dp = na; if(flag & Fesign) ex = -ex; dp += ex; if(dp < -Maxe){ errno = ERANGE; goto ret0; /* underflow by exp */ } else if(dp > +Maxe) goto retinf; /* overflow by exp */ /* * normalize the decimal ascii number * to range .[5-9][0-9]* e0 */ bp = 0; /* binary exponent */ while(dp > 0) divascii(a, &na, &dp, &bp); while(dp < 0 || a[0] < '5') mulascii(a, &na, &dp, &bp); /* close approx by naive conversion */ mid[0] = 0; mid[1] = 1; for(i=0; (c=a[i]); i++) { mid[0] = mid[0]*10 + (c-'0'); mid[1] = mid[1]*10; if(i >= 8) break; } low[0] = umuldiv(mid[0], One, mid[1]); hig[0] = umuldiv(mid[0]+1, One, mid[1]); for(i=1; i>= 1; } frnorm(mid); /* compare */ c = fpcmp(a, mid); if(c > 0) { c = 1; for(i=0; i= Sigbit/2) { mid[Prec-1] += Sigbit; frnorm(mid); } goto out; ret0: return 0; retnan: return __NaN(); retinf: /* * Unix strtod requires these. Plan 9 would return Inf(0) or Inf(-1). */ errno = ERANGE; if(flag & Fsign) return -HUGE_VAL; return HUGE_VAL; out: d = 0; for(i=0; i0; i--) { f[i] += c; c = f[i] >> Nbits; f[i] &= One-1; } f[0] += c; } static int fpcmp(char *a, ulong* f) { ulong tf[Prec]; int i, d, c; for(i=0; i> Nbits) + '0'; tf[0] &= One-1; /* compare next digit */ c = *a; if(c == 0) { if('0' < d) return -1; if(tf[0] != 0) goto cont; for(i=1; i d) return +1; if(c < d) return -1; a++; cont:; } } static void divby(char *a, int *na, int b) { int n, c; char *p; p = a; n = 0; while(n>>b == 0) { c = *a++; if(c == 0) { while(n) { c = n*10; if(c>>b) break; n = c; } goto xx; } n = n*10 + c-'0'; (*na)--; } for(;;) { c = n>>b; n -= c<>b; n -= c<= (int)(nelem(tab1))) d = (int)(nelem(tab1))-1; t = tab1 + d; b = t->bp; if(memcmp(a, t->cmp, t->siz) > 0) d--; *dp -= d; *bp += b; divby(a, na, b); } static void mulby(char *a, char *p, char *q, int b) { int n, c; n = 0; *p = 0; for(;;) { q--; if(q < a) break; c = *q - '0'; c = (c<= (int)(nelem(tab2))) d = (int)(nelem(tab2))-1; t = tab2 + d; b = t->bp; if(memcmp(a, t->cmp, t->siz) < 0) d--; p = a + *na; *bp -= b; *dp += d; *na += d; mulby(a, p+d, p, b); } static int xcmp(char *a, char *b) { int c1, c2; while((c1 = *b++)) { c2 = *a++; if(isupper(c2)) c2 = tolower(c2); if(c1 != c2) return 1; } return 0; } drawterm-20170818/libc/strtod.h000066400000000000000000000001701314554504700162220ustar00rootroot00000000000000extern double __NaN(void); extern double __Inf(int); extern double __isNaN(double); extern double __isInf(double, int); drawterm-20170818/libc/strtoll.c000066400000000000000000000024501314554504700164040ustar00rootroot00000000000000#include #include #define VLONG_MAX ((vlong)~(((uvlong)1)<<63)) #define VLONG_MIN ((vlong)(((uvlong)1)<<63)) vlong strtoll(const char *nptr, char **endptr, int base) { char *p; vlong n, nn, m; int c, ovfl, v, neg, ndig; p = (char*)nptr; neg = 0; n = 0; ndig = 0; ovfl = 0; /* * White space */ for(;; p++) { switch(*p) { case ' ': case '\t': case '\n': case '\f': case '\r': case '\v': continue; } break; } /* * Sign */ if(*p=='-' || *p=='+') if(*p++ == '-') neg = 1; /* * Base */ if(base==0){ base = 10; if(*p == '0') { base = 8; if(p[1]=='x' || p[1]=='X') { p += 2; base = 16; } } } else if(base==16 && *p=='0') { if(p[1]=='x' || p[1]=='X') p += 2; } else if(base<0 || 36= base) break; if(n > m) ovfl = 1; nn = n*base + v; if(nn < n) ovfl = 1; n = nn; } Return: if(ndig == 0) p = (char*)nptr; if(endptr) *endptr = p; if(ovfl){ if(neg) return VLONG_MIN; return VLONG_MAX; } if(neg) return -n; return n; } drawterm-20170818/libc/sysfatal.c000066400000000000000000000007371314554504700165350ustar00rootroot00000000000000#include #include static void _sysfatalimpl(char *fmt, va_list arg) { char buf[1024]; vseprint(buf, buf+sizeof(buf), fmt, arg); if(argv0) fprint(2, "%s: %s\n", argv0, buf); else fprint(2, "%s\n", buf); #undef write write(2, buf, strlen(buf)); write(2, "\n", 1); panic("sysfatal"); } void (*_sysfatal)(char *fmt, va_list arg) = _sysfatalimpl; void sysfatal(char *fmt, ...) { va_list arg; va_start(arg, fmt); (*_sysfatal)(fmt, arg); va_end(arg); } drawterm-20170818/libc/time.c000066400000000000000000000015561314554504700156450ustar00rootroot00000000000000#include #include /* * After a fork with fd's copied, both fd's are pointing to * the same Chan structure. Since the offset is kept in the Chan * structure, the seek's and read's in the two processes can * compete at moving the offset around. Hence the unusual loop * in the middle of this routine. */ static long oldtime(long *tp) { char b[20]; static int f = -1; int i, retries; long t; memset(b, 0, sizeof(b)); for(retries = 0; retries < 100; retries++){ if(f < 0) f = open("/dev/time", OREAD|OCEXEC); if(f < 0) break; if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof(b))) < 0){ close(f); f = -1; } else { if(i != 0) break; } } t = atol(b); if(tp) *tp = t; return t; } long time(long *tp) { vlong t; t = nsec()/((vlong)1000000000); if(t == 0) t = oldtime(0); if(tp != nil) *tp = t; return t; } drawterm-20170818/libc/tokenize.c000066400000000000000000000032331314554504700165310ustar00rootroot00000000000000#include #include static char qsep[] = " \t\r\n"; static char* qtoken(char *s, char *sep) { int quoting; char *t; quoting = 0; t = s; /* s is output string, t is input string */ while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){ if(*t != '\''){ *s++ = *t++; continue; } /* *t is a quote */ if(!quoting){ quoting = 1; t++; continue; } /* quoting and we're on a quote */ if(t[1] != '\''){ /* end of quoted section; absorb closing quote */ t++; quoting = 0; continue; } /* doubled quote; fold one quote into two */ t++; *s++ = *t++; } if(*s != '\0'){ *s = '\0'; if(t == s) t++; } return t; } static char* etoken(char *t, char *sep) { int quoting; /* move to end of next token */ quoting = 0; while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){ if(*t != '\''){ t++; continue; } /* *t is a quote */ if(!quoting){ quoting = 1; t++; continue; } /* quoting and we're on a quote */ if(t[1] != '\''){ /* end of quoted section; absorb closing quote */ t++; quoting = 0; continue; } /* doubled quote; fold one quote into two */ t += 2; } return t; } int gettokens(char *s, char **args, int maxargs, char *sep) { int nargs; for(nargs=0; nargs #include ulong truerand(void) { ulong x; static int randfd = -1; if(randfd < 0) randfd = open("/dev/random", OREAD|OCEXEC); if(randfd < 0) sysfatal("can't open /dev/random"); if(read(randfd, &x, sizeof(x)) != sizeof(x)) sysfatal("can't read /dev/random"); return x; } drawterm-20170818/libc/u16.c000066400000000000000000000014671314554504700153230ustar00rootroot00000000000000#include #include static char t16e[] = "0123456789ABCDEF"; int dec16(uchar *out, int lim, char *in, int n) { int c, w = 0, i = 0; uchar *start = out; uchar *eout = out + lim; while(n-- > 0){ c = *in++; if('0' <= c && c <= '9') c = c - '0'; else if('a' <= c && c <= 'z') c = c - 'a' + 10; else if('A' <= c && c <= 'Z') c = c - 'A' + 10; else continue; w = (w<<4) + c; i++; if(i == 2){ if(out + 1 > eout) goto exhausted; *out++ = w; w = 0; i = 0; } } exhausted: return out - start; } int enc16(char *out, int lim, uchar *in, int n) { uint c; char *eout = out + lim; char *start = out; while(n-- > 0){ c = *in++; if(out + 2 >= eout) goto exhausted; *out++ = t16e[c>>4]; *out++ = t16e[c&0xf]; } exhausted: *out = 0; return out - start; } drawterm-20170818/libc/u32.c000066400000000000000000000045561314554504700153230ustar00rootroot00000000000000#include #include int dec32(uchar *dest, int ndest, char *src, int nsrc) { char *s, *tab; uchar *start; int i, u[8]; if(ndest+1 < (5*nsrc+7)/8) return -1; start = dest; tab = "23456789abcdefghijkmnpqrstuvwxyz"; while(nsrc>=8){ for(i=0; i<8; i++){ s = strchr(tab,(int)src[i]); u[i] = s ? s-tab : 0; } *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2)); *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); *dest++ = ((0x7 & u[6])<<5) | u[7]; src += 8; nsrc -= 8; } if(nsrc > 0){ if(nsrc == 1 || nsrc == 3 || nsrc == 6) return -1; for(i=0; i>2)); if(nsrc == 2) goto out; *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); if(nsrc == 4) goto out; *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); if(nsrc == 5) goto out; *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); } out: return dest-start; } int enc32(char *dest, int ndest, uchar *src, int nsrc) { char *tab, *start; int j; if(ndest <= (8*nsrc+4)/5 ) return -1; start = dest; tab = "23456789abcdefghijkmnpqrstuvwxyz"; while(nsrc>=5){ j = (0x1f & (src[0]>>3)); *dest++ = tab[j]; j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6)); *dest++ = tab[j]; j = (0x1f & (src[1]>>1)); *dest++ = tab[j]; j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4)); *dest++ = tab[j]; j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7)); *dest++ = tab[j]; j = (0x1f & (src[3]>>2)); *dest++ = tab[j]; j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5)); *dest++ = tab[j]; j = (0x1f & (src[4])); *dest++ = tab[j]; src += 5; nsrc -= 5; } if(nsrc){ j = (0x1f & (src[0]>>3)); *dest++ = tab[j]; j = (0x1c & (src[0]<<2)); if(nsrc == 1) goto out; j |= (0x03 & (src[1]>>6)); *dest++ = tab[j]; j = (0x1f & (src[1]>>1)); if(nsrc == 2) goto out; *dest++ = tab[j]; j = (0x10 & (src[1]<<4)); if(nsrc == 3) goto out; j |= (0x0f & (src[2]>>4)); *dest++ = tab[j]; j = (0x1e & (src[2]<<1)); if(nsrc == 4) goto out; j |= (0x01 & (src[3]>>7)); *dest++ = tab[j]; j = (0x1f & (src[3]>>2)); *dest++ = tab[j]; j = (0x18 & (src[3]<<3)); out: *dest++ = tab[j]; } *dest = 0; return dest-start; } drawterm-20170818/libc/u64.c000066400000000000000000000063221314554504700153210ustar00rootroot00000000000000#include #include enum { INVAL= 255 }; static uchar t64d[256] = { INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, 62,INVAL,INVAL,INVAL, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL }; static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int dec64(uchar *out, int lim, char *in, int n) { ulong b24; uchar *start = out; uchar *e = out + lim; int i, c; b24 = 0; i = 0; while(n-- > 0){ c = t64d[*(uchar*)in++]; if(c == INVAL) continue; switch(i){ case 0: b24 = c<<18; break; case 1: b24 |= c<<12; break; case 2: b24 |= c<<6; break; case 3: if(out + 3 > e) goto exhausted; b24 |= c; *out++ = b24>>16; *out++ = b24>>8; *out++ = b24; i = -1; break; } i++; } switch(i){ case 2: if(out + 1 > e) goto exhausted; *out++ = b24>>16; break; case 3: if(out + 2 > e) goto exhausted; *out++ = b24>>16; *out++ = b24>>8; break; } exhausted: return out - start; } int enc64(char *out, int lim, uchar *in, int n) { int i; ulong b24; char *start = out; char *e = out + lim; for(i = n/3; i > 0; i--){ b24 = (*in++)<<16; b24 |= (*in++)<<8; b24 |= *in++; if(out + 4 >= e) goto exhausted; *out++ = t64e[(b24>>18)]; *out++ = t64e[(b24>>12)&0x3f]; *out++ = t64e[(b24>>6)&0x3f]; *out++ = t64e[(b24)&0x3f]; } switch(n%3){ case 2: b24 = (*in++)<<16; b24 |= (*in)<<8; if(out + 4 >= e) goto exhausted; *out++ = t64e[(b24>>18)]; *out++ = t64e[(b24>>12)&0x3f]; *out++ = t64e[(b24>>6)&0x3f]; *out++ = '='; break; case 1: b24 = (*in)<<16; if(out + 4 >= e) goto exhausted; *out++ = t64e[(b24>>18)]; *out++ = t64e[(b24>>12)&0x3f]; *out++ = '='; *out++ = '='; break; } exhausted: *out = 0; return out - start; } drawterm-20170818/libc/utf.h000066400000000000000000000030031314554504700154770ustar00rootroot00000000000000#ifndef _UTFH_ #define _UTFH_ 1 typedef unsigned int Rune; /* 32 bits */ enum { UTFmax = 4, /* maximum bytes per rune */ Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ Runeself = 0x80, /* rune and UTF sequences are the same (<) */ Runeerror = 0xFFFD, /* decoding error in UTF */ Runemax = 0x10FFFF, /* 21-bit rune */ Runemask = 0x1FFFFF, /* bits used by runes (see grep) */ }; /* * rune routines */ extern int runetochar(char*, Rune*); extern int chartorune(Rune*, char*); extern int runelen(long); extern int runenlen(Rune*, int); extern int fullrune(char*, int); extern int utflen(char*); extern int utfnlen(char*, long); extern char* utfrune(char*, long); extern char* utfrrune(char*, long); extern char* utfutf(char*, char*); extern char* utfecpy(char*, char*, char*); extern Rune* runestrcat(Rune*, Rune*); extern Rune* runestrchr(Rune*, Rune); extern int runestrcmp(Rune*, Rune*); extern Rune* runestrcpy(Rune*, Rune*); extern Rune* runestrncpy(Rune*, Rune*, long); extern Rune* runestrecpy(Rune*, Rune*, Rune*); extern Rune* runestrdup(Rune*); extern Rune* runestrncat(Rune*, Rune*, long); extern int runestrncmp(Rune*, Rune*, long); extern Rune* runestrrchr(Rune*, Rune); extern long runestrlen(Rune*); extern Rune* runestrstr(Rune*, Rune*); extern Rune tolowerrune(Rune); extern Rune totitlerune(Rune); extern Rune toupperrune(Rune); extern int isalpharune(Rune); extern int islowerrune(Rune); extern int isspacerune(Rune); extern int istitlerune(Rune); extern int isupperrune(Rune); #endif drawterm-20170818/libc/utfdef.h000066400000000000000000000005171314554504700161650ustar00rootroot00000000000000#define uchar _utfuchar #define ushort _utfushort #define uint _utfuint #define ulong _utfulong #define vlong _utfvlong #define uvlong _utfuvlong typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; #define nelem(x) (sizeof(x)/sizeof((x)[0])) #define nil ((void*)0) drawterm-20170818/libc/utfecpy.c000066400000000000000000000004341314554504700163600ustar00rootroot00000000000000#include #include char* utfecpy(char *to, char *e, char *from) { char *end; if(to >= e) return to; end = memccpy(to, from, '\0', e - to); if(end == nil){ end = e-1; while(end>to && (*--end&0xC0)==0x80) ; *end = '\0'; }else{ end--; } return end; } drawterm-20170818/libc/utflen.c000066400000000000000000000003621314554504700161760ustar00rootroot00000000000000#include #include int utflen(char *s) { int c; long n; Rune rune; n = 0; for(;;) { c = *(uchar*)s; if(c < Runeself) { if(c == 0) return n; s++; } else s += chartorune(&rune, s); n++; } return 0; } drawterm-20170818/libc/utfnlen.c000066400000000000000000000004751314554504700163610ustar00rootroot00000000000000#include #include int utfnlen(char *s, long m) { int c; long n; Rune rune; char *es; es = s + m; for(n = 0; s < es; n++) { c = *(uchar*)s; if(c < Runeself){ if(c == '\0') break; s++; continue; } if(!fullrune(s, es-s)) break; s += chartorune(&rune, s); } return n; } drawterm-20170818/libc/utfrrune.c000066400000000000000000000006361314554504700165570ustar00rootroot00000000000000#include #include char* utfrrune(char *s, long c) { long c1; Rune r; char *s1; if(c < Runesync) /* not part of utf sequence */ return strrchr(s, c); s1 = 0; for(;;) { c1 = *(uchar*)s; if(c1 < Runeself) { /* one byte rune */ if(c1 == 0) return s1; if(c1 == c) s1 = s; s++; continue; } c1 = chartorune(&r, s); if(r == c) s1 = s; s += c1; } return 0; } drawterm-20170818/libc/utfrune.c000066400000000000000000000006211314554504700163670ustar00rootroot00000000000000#include #include char* utfrune(char *s, long c) { long c1; Rune r; int n; if(c < Runesync) /* not part of utf sequence */ return strchr(s, c); for(;;) { c1 = *(uchar*)s; if(c1 < Runeself) { /* one byte rune */ if(c1 == 0) return 0; if(c1 == c) return s; s++; continue; } n = chartorune(&r, s); if(r == c) return s; s += n; } return 0; } drawterm-20170818/libc/utfutf.c000066400000000000000000000006071314554504700162200ustar00rootroot00000000000000#include #include /* * Return pointer to first occurrence of s2 in s1, * 0 if none */ char* utfutf(char *s1, char *s2) { char *p; long f, n1, n2; Rune r; n1 = chartorune(&r, s2); f = r; if(f <= Runesync) /* represents self */ return strstr(s1, s2); n2 = strlen(s2); for(p=s1; (p=utfrune(p, f)); p+=n1) if(strncmp(p, s2, n2) == 0) return p; return 0; } drawterm-20170818/libc/vfprint.c000066400000000000000000000004471314554504700163750ustar00rootroot00000000000000#include #include #include "fmtdef.h" int vfprint(int fd, char *fmt, va_list args) { Fmt f; char buf[256]; int n; fmtfdinit(&f, fd, buf, sizeof(buf)); VA_COPY(f.args,args); n = dofmt(&f, fmt); VA_END(f.args); if(n > 0 && __fmtFdFlush(&f) == 0) return -1; return n; } drawterm-20170818/libc/vseprint.c000066400000000000000000000005461314554504700165570ustar00rootroot00000000000000#include #include #include "fmtdef.h" char* vseprint(char *buf, char *e, char *fmt, va_list args) { Fmt f; if(e <= buf) return nil; f.runes = 0; f.start = buf; f.to = buf; f.stop = e - 1; f.flush = 0; f.farg = nil; f.nfmt = 0; VA_COPY(f.args,args); dofmt(&f, fmt); VA_END(f.args); *(char*)f.to = '\0'; return (char*)f.to; } drawterm-20170818/libc/vsmprint.c000066400000000000000000000017521314554504700165670ustar00rootroot00000000000000#include #include #include "fmtdef.h" static int fmtStrFlush(Fmt *f) { char *s; int n; if(f->start == nil) return 0; n = (uintptr)f->farg; n *= 2; s = (char*)f->start; f->start = realloc(s, n); if(f->start == nil){ f->farg = nil; f->to = nil; f->stop = nil; free(s); return 0; } f->farg = (void*)(uintptr)n; f->to = (char*)f->start + ((char*)f->to - s); f->stop = (char*)f->start + n - 1; return 1; } int fmtstrinit(Fmt *f) { int n; memset(f, 0, sizeof *f); f->runes = 0; n = 32; f->start = malloc(n); if(f->start == nil) return -1; f->to = f->start; f->stop = (char*)f->start + n - 1; f->flush = fmtStrFlush; f->farg = (void*)(uintptr)n; f->nfmt = 0; return 0; } /* * print into an allocated string buffer */ char* vsmprint(char *fmt, va_list args) { Fmt f; int n; if(fmtstrinit(&f) < 0) return nil; VA_COPY(f.args,args); n = dofmt(&f, fmt); VA_END(f.args); if(n < 0){ free(f.start); return nil; } return fmtstrflush(&f); } drawterm-20170818/libc/vsnprint.c000066400000000000000000000005601314554504700165640ustar00rootroot00000000000000#include #include #include "fmtdef.h" int vsnprint(char *buf, int len, char *fmt, va_list args) { Fmt f; if(len <= 0) return -1; f.runes = 0; f.start = buf; f.to = buf; f.stop = buf + len - 1; f.flush = 0; f.farg = nil; f.nfmt = 0; VA_COPY(f.args,args); dofmt(&f, fmt); VA_END(f.args); *(char*)f.to = '\0'; return (char*)f.to - buf; } drawterm-20170818/libdraw/000077500000000000000000000000001314554504700152475ustar00rootroot00000000000000drawterm-20170818/libdraw/Makefile000066400000000000000000000004451314554504700167120ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libdraw.a OFILES=\ alloc.$O\ arith.$O\ bytesperline.$O\ chan.$O\ defont.$O\ drawrepl.$O\ icossin.$O\ icossin2.$O\ rectclip.$O\ rgb.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/libdraw/alloc.c000066400000000000000000000077771314554504700165270ustar00rootroot00000000000000#include #include #include Image* allocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val) { return _allocimage(nil, d, r, chan, repl, val, 0, 0); } Image* _allocimage(Image *ai, Display *d, Rectangle r, ulong chan, int repl, ulong val, int screenid, int refresh) { uchar *a; char *err; Image *i; Rectangle clipr; int id; int depth; err = 0; i = 0; if(chan == 0){ werrstr("bad channel descriptor"); return nil; } depth = chantodepth(chan); if(depth == 0){ err = "bad channel descriptor"; Error: if(err) werrstr("allocimage: %s", err); else werrstr("allocimage: %r"); free(i); return 0; } /* flush pending data so we don't get error allocating the image */ flushimage(d, 0); a = bufimage(d, 1+4+4+1+4+1+4*4+4*4+4); if(a == 0) goto Error; d->imageid++; id = d->imageid; a[0] = 'b'; BPLONG(a+1, id); BPLONG(a+5, screenid); a[9] = refresh; BPLONG(a+10, chan); a[14] = repl; BPLONG(a+15, r.min.x); BPLONG(a+19, r.min.y); BPLONG(a+23, r.max.x); BPLONG(a+27, r.max.y); if(repl) /* huge but not infinite, so various offsets will leave it huge, not overflow */ clipr = Rect(-0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF); else clipr = r; BPLONG(a+31, clipr.min.x); BPLONG(a+35, clipr.min.y); BPLONG(a+39, clipr.max.x); BPLONG(a+43, clipr.max.y); BPLONG(a+47, val); if(flushimage(d, 0) < 0) goto Error; if(ai) i = ai; else{ i = malloc(sizeof(Image)); if(i == nil){ a = bufimage(d, 1+4); if(a){ a[0] = 'f'; BPLONG(a+1, id); flushimage(d, 0); } goto Error; } } i->display = d; i->id = id; i->depth = depth; i->chan = chan; i->r = r; i->clipr = clipr; i->repl = repl; i->screen = 0; i->next = 0; return i; } Image* namedimage(Display *d, char *name) { uchar *a; char *err, buf[12*12+1]; Image *i; int id, n; ulong chan; err = 0; i = 0; n = strlen(name); if(n >= 256){ err = "name too long"; Error: if(err) werrstr("namedimage: %s", err); else werrstr("namedimage: %r"); if(i) free(i); return 0; } /* flush pending data so we don't get error allocating the image */ flushimage(d, 0); a = bufimage(d, 1+4+1+n); if(a == 0) goto Error; d->imageid++; id = d->imageid; a[0] = 'n'; BPLONG(a+1, id); a[5] = n; memmove(a+6, name, n); if(flushimage(d, 0) < 0) goto Error; if(pread(d->ctlfd, buf, sizeof buf, 0) < 12*12) goto Error; buf[12*12] = '\0'; i = malloc(sizeof(Image)); if(i == nil){ Error1: a = bufimage(d, 1+4); if(a){ a[0] = 'f'; BPLONG(a+1, id); flushimage(d, 0); } goto Error; } i->display = d; i->id = id; if((chan=strtochan(buf+2*12))==0){ werrstr("bad channel '%.12s' from devdraw", buf+2*12); goto Error1; } i->chan = chan; i->depth = chantodepth(chan); i->repl = atoi(buf+3*12); i->r.min.x = atoi(buf+4*12); i->r.min.y = atoi(buf+5*12); i->r.max.x = atoi(buf+6*12); i->r.max.y = atoi(buf+7*12); i->clipr.min.x = atoi(buf+8*12); i->clipr.min.y = atoi(buf+9*12); i->clipr.max.x = atoi(buf+10*12); i->clipr.max.y = atoi(buf+11*12); i->screen = 0; i->next = 0; return i; } int nameimage(Image *i, char *name, int in) { uchar *a; int n; n = strlen(name); a = bufimage(i->display, 1+4+1+1+n); if(a == 0) return 0; a[0] = 'N'; BPLONG(a+1, i->id); a[5] = in; a[6] = n; memmove(a+7, name, n); if(flushimage(i->display, 0) < 0) return 0; return 1; } int _freeimage1(Image *i) { uchar *a; Display *d; Image *w; if(i == 0) return 0; /* make sure no refresh events occur on this if we block in the write */ d = i->display; /* flush pending data so we don't get error deleting the image */ flushimage(d, 0); a = bufimage(d, 1+4); if(a == 0) return -1; a[0] = 'f'; BPLONG(a+1, i->id); if(i->screen){ w = d->windows; if(w == i) d->windows = i->next; else while(w){ if(w->next == i){ w->next = i->next; break; } w = w->next; } } if(flushimage(d, i->screen!=0) < 0) return -1; return 0; } int freeimage(Image *i) { int ret; ret = _freeimage1(i); free(i); return ret; } drawterm-20170818/libdraw/arith.c000066400000000000000000000054271314554504700165320ustar00rootroot00000000000000#include #include #include Point Pt(int x, int y) { Point p; p.x = x; p.y = y; return p; } Rectangle Rect(int x, int y, int bx, int by) { Rectangle r; r.min.x = x; r.min.y = y; r.max.x = bx; r.max.y = by; return r; } Rectangle Rpt(Point min, Point max) { Rectangle r; r.min = min; r.max = max; return r; } Point addpt(Point a, Point b) { a.x += b.x; a.y += b.y; return a; } Point subpt(Point a, Point b) { a.x -= b.x; a.y -= b.y; return a; } Rectangle insetrect(Rectangle r, int n) { r.min.x += n; r.min.y += n; r.max.x -= n; r.max.y -= n; return r; } Point divpt(Point a, int b) { a.x /= b; a.y /= b; return a; } Point mulpt(Point a, int b) { a.x *= b; a.y *= b; return a; } Rectangle rectsubpt(Rectangle r, Point p) { r.min.x -= p.x; r.min.y -= p.y; r.max.x -= p.x; r.max.y -= p.y; return r; } Rectangle rectaddpt(Rectangle r, Point p) { r.min.x += p.x; r.min.y += p.y; r.max.x += p.x; r.max.y += p.y; return r; } int eqpt(Point p, Point q) { return p.x==q.x && p.y==q.y; } int eqrect(Rectangle r, Rectangle s) { return r.min.x==s.min.x && r.max.x==s.max.x && r.min.y==s.min.y && r.max.y==s.max.y; } int rectXrect(Rectangle r, Rectangle s) { return r.min.x=r.min.x && p.x=r.min.y && p.ymin.x > r2.min.x) r1->min.x = r2.min.x; if(r1->min.y > r2.min.y) r1->min.y = r2.min.y; if(r1->max.x < r2.max.x) r1->max.x = r2.max.x; if(r1->max.y < r2.max.y) r1->max.y = r2.max.y; } ulong drawld2chan[] = { GREY1, GREY2, GREY4, CMAP8, }; int log2[] = { -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5 }; ulong setalpha(ulong color, uchar alpha) { int red, green, blue; red = (color >> 3*8) & 0xFF; green = (color >> 2*8) & 0xFF; blue = (color >> 1*8) & 0xFF; /* ignore incoming alpha */ red = (red * alpha)/255; green = (green * alpha)/255; blue = (blue * alpha)/255; return (red<<3*8) | (green<<2*8) | (blue<<1*8) | (alpha<<0*8); } Point ZP; Rectangle ZR; int Rfmt(Fmt *f) { Rectangle r; r = va_arg(f->args, Rectangle); return fmtprint(f, "%P %P", r.min, r.max); } int Pfmt(Fmt *f) { Point p; p = va_arg(f->args, Point); return fmtprint(f, "[%d %d]", p.x, p.y); } drawterm-20170818/libdraw/bytesperline.c000066400000000000000000000011511314554504700201160ustar00rootroot00000000000000#include #include #include static int unitsperline(Rectangle r, int d, int bitsperunit) { ulong l, t; if(d <= 0 || d > 32) /* being called wrong. d is image depth. */ abort(); if(r.min.x >= 0){ l = (r.max.x*d+bitsperunit-1)/bitsperunit; l -= (r.min.x*d)/bitsperunit; }else{ /* make positive before divide */ t = (-r.min.x*d+bitsperunit-1)/bitsperunit; l = t+(r.max.x*d+bitsperunit-1)/bitsperunit; } return l; } int wordsperline(Rectangle r, int d) { return unitsperline(r, d, 8*sizeof(ulong)); } int bytesperline(Rectangle r, int d) { return unitsperline(r, d, 8); } drawterm-20170818/libdraw/chan.c000066400000000000000000000021771314554504700163330ustar00rootroot00000000000000#include #include #include static char channames[] = "rgbkamx"; char* chantostr(char *buf, ulong cc) { ulong c, rc; char *p; if(chantodepth(cc) == 0) return nil; /* reverse the channel descriptor so we can easily generate the string in the right order */ rc = 0; for(c=cc; c; c>>=8){ rc <<= 8; rc |= c&0xFF; } p = buf; for(c=rc; c; c>>=8) { *p++ = channames[TYPE(c)]; *p++ = '0'+NBITS(c); } *p = 0; return buf; } /* avoid pulling in ctype when using with drawterm etc. */ static int xisspace(char c) { return c==' ' || c== '\t' || c=='\r' || c=='\n'; } ulong strtochan(char *s) { char *p, *q; ulong c; int t, n; c = 0; p=s; while(*p && xisspace(*p)) p++; while(*p && !xisspace(*p)){ if((q = strchr(channames, p[0])) == nil) return 0; t = q-channames; if(p[1] < '0' || p[1] > '9') return 0; n = p[1]-'0'; c = (c<<8) | __DC(t, n); p += 2; } return c; } int chantodepth(ulong c) { int n; for(n=0; c; c>>=8){ if(TYPE(c) >= NChan || NBITS(c) > 8 || NBITS(c) <= 0) return 0; n += NBITS(c); } if(n==0 || (n>8 && n%8) || (n<8 && 8%n)) return 0; return n; } drawterm-20170818/libdraw/defont.c000066400000000000000000000735111314554504700167010ustar00rootroot00000000000000#include #include #include /* * lucm/latin1.9, in uncompressed form */ uchar defontdata[] = { 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x32,0x33,0x30,0x34,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x35,0x20,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x30,0x06,0x06,0x03,0x42,0x40,0x00,0x00,0x00,0x18,0x03,0x03, 0x02,0x43,0x00,0x60,0x60,0x48,0x00,0x0d,0x0c,0x01,0x81,0x80,0xd0,0x90,0x00,0x00, 0x18,0x01,0x81,0x81,0x40,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x7f,0x9c,0x1c, 0x0e,0x07,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x70, 0x38,0x1c,0x0e,0x04,0x81,0xc1,0xc0,0x70,0x00,0x1c,0x1c,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0x80,0xc0,0x63,0xe3, 0xf1,0xf8,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x7f,0xff,0xff,0x1f,0x8f, 0xc7,0xe3,0xf1,0xfb,0x7e,0x3e,0x3f,0x8f,0xff,0xe3,0xe3,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x0c,0x18,0x09,0x05,0x82,0x40,0xc0,0x00,0x00,0x06,0x0c,0x04, 0x82,0x40,0xc1,0x80,0x90,0x48,0x00,0x16,0x03,0x06,0x02,0x41,0x60,0x90,0x00,0x00, 0x06,0x06,0x02,0x41,0x41,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x7f,0xa0,0x10, 0x08,0x04,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x48, 0x24,0x12,0x09,0x06,0x82,0x01,0x00,0x90,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x04,0x80,0x00,0x40,0x00,0x00,0x38,0x06,0x18,0x00,0x00,0x00,0x00,0x00, 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x07,0xc6,0x01,0xf0,0x00,0x00,0x0c,0x00,0x18,0x00,0x00,0x30,0x00,0x3c, 0x00,0x60,0x06,0x01,0x8c,0x07,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe0,0xc3,0xc0,0x01,0x54,0x9c,0xc0,0x5f,0xef, 0xf7,0xfb,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0x7f,0xff,0xff,0x6f,0xb7, 0xdb,0xed,0xf6,0xf9,0x7d,0xfe,0xff,0x6f,0xff,0xdf,0xef,0xff,0xff,0xff,0xff,0xff, 0xff,0x00,0x01,0x00,0x00,0x00,0x00,0x30,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x30,0x06,0x06,0x06,0x82,0x80,0xc0,0x00, 0x00,0x18,0x03,0x03,0x02,0x41,0x80,0x30,0x30,0x24,0x76,0x0d,0x0c,0x00,0xc0,0xc0, 0xd0,0x50,0x00,0x00,0x18,0x01,0x81,0x81,0x40,0x30,0x00,0x28,0x0f,0x7f,0xbc,0x1c, 0x0e,0x07,0x03,0xc0,0x10,0x70,0x24,0x10,0x09,0x07,0x03,0x80,0xe0,0x70,0x90,0x48, 0x24,0x12,0x09,0x05,0x81,0x81,0xc0,0x80,0x70,0x18,0x1c,0x07,0x01,0xc1,0xc0,0x90, 0x00,0x0c,0x04,0x84,0x83,0xe1,0xc0,0xe0,0x38,0x0c,0x0c,0x02,0x00,0x00,0x00,0x00, 0x00,0x06,0x1c,0x06,0x0f,0x87,0xc0,0x63,0xf8,0x78,0xfe,0x3e,0x0e,0x00,0x00,0x00, 0x00,0x00,0x00,0x7c,0x1c,0x0c,0x1f,0x03,0xc7,0xc3,0xf1,0xf8,0x3c,0x63,0x3f,0x0f, 0x8c,0x66,0x06,0x19,0x84,0x78,0x7e,0x1e,0x1f,0x07,0xcf,0xf3,0x1b,0x0d,0x86,0x63, 0x61,0x9f,0xc6,0x06,0x00,0x30,0x00,0x00,0x10,0x00,0x18,0x00,0x00,0x30,0x00,0x60, 0x00,0x60,0x06,0x01,0x8c,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80, 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0xc0,0x60,0x00,0xaa,0xb6,0xc0,0x43,0xe3, 0xf1,0xf8,0xfc,0x3f,0xef,0x8f,0xdb,0xef,0xf6,0xf8,0xfb,0xff,0x1f,0x8f,0x6f,0xb7, 0xdb,0xed,0xf6,0xfa,0x7e,0x7e,0x3f,0x7f,0x8f,0xe7,0xe3,0xf8,0xfe,0x3e,0x3f,0x6f, 0x00,0x00,0x01,0x01,0xc8,0x0b,0x0c,0x30,0x7c,0x14,0x0f,0x0f,0x00,0x00,0x00,0x00, 0x78,0x00,0x1c,0x00,0x0f,0x07,0x81,0x80,0x00,0x7c,0x00,0x00,0x1c,0x0f,0x80,0x04, 0x42,0x23,0x90,0x00,0x18,0x0c,0x06,0x03,0x01,0x80,0xc0,0x3c,0x3c,0x3f,0x1f,0x8f, 0xc7,0xe7,0xe3,0xf1,0xf8,0xfc,0x7c,0x30,0x8f,0x07,0x83,0xc1,0xe0,0xf0,0x00,0x3d, 0x31,0x98,0xcc,0x66,0x36,0x19,0x80,0xcc,0x0c,0x18,0x09,0x0b,0x02,0x81,0x20,0x00, 0x00,0x06,0x0c,0x04,0x82,0x40,0x60,0xc0,0x48,0x24,0x18,0x16,0x03,0x03,0x01,0x21, 0x60,0x50,0x00,0x00,0x06,0x06,0x02,0x41,0x40,0xc1,0x80,0x28,0x87,0x7f,0x84,0x10, 0x08,0x04,0x02,0x40,0x38,0x48,0x24,0x10,0x09,0x04,0x04,0x81,0x00,0x80,0x90,0x48, 0x24,0x12,0x09,0x04,0x80,0x41,0x00,0x80,0x40,0x04,0x10,0x04,0x02,0x01,0x20,0x90, 0x00,0x0c,0x04,0x84,0x86,0x53,0x65,0xb0,0x08,0x18,0x06,0x0a,0x80,0x00,0x00,0x00, 0x00,0x0c,0x36,0x0e,0x19,0xcc,0xe0,0xe3,0xf8,0xcc,0xfe,0x63,0x1b,0x00,0x00,0x00, 0x00,0x00,0x00,0xc6,0x62,0x0c,0x19,0x86,0x66,0x63,0x01,0x80,0x66,0x63,0x0c,0x01, 0x8c,0xc6,0x06,0x19,0xc4,0xcc,0x63,0x33,0x19,0x8c,0x61,0x83,0x1b,0x0d,0x86,0x63, 0x61,0x80,0xc6,0x03,0x00,0x30,0x30,0x00,0x1c,0x00,0x18,0x00,0x00,0x30,0x00,0x60, 0x00,0x60,0x00,0x00,0x0c,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80, 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0xc0,0x60,0x01,0x54,0x86,0xc0,0x7b,0xef, 0xf7,0xfb,0xfd,0xbf,0xc7,0xb7,0xdb,0xef,0xf6,0xfb,0xfb,0x7e,0xff,0x7f,0x6f,0xb7, 0xdb,0xed,0xf6,0xfb,0x7f,0xbe,0xff,0x7f,0xbf,0xfb,0xef,0xfb,0xfd,0xfe,0xdf,0x6f, 0xff,0x00,0x07,0x83,0x24,0x13,0x0c,0x30,0xc6,0x00,0x10,0x81,0x80,0x00,0x00,0x00, 0x84,0x00,0x22,0x00,0x01,0x80,0xc0,0x00,0x00,0xf4,0x00,0x00,0x2c,0x18,0xc0,0x0c, 0x46,0x20,0x90,0x00,0x18,0x0c,0x06,0x03,0x01,0x80,0xc0,0x70,0x66,0x30,0x18,0x0c, 0x06,0x01,0x80,0xc0,0x60,0x30,0x66,0x38,0x99,0x8c,0xc6,0x63,0x31,0x98,0x00,0x66, 0x31,0x98,0xcc,0x66,0x36,0x19,0x80,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,0xff,0x7f,0xb8,0x1c, 0x0e,0x07,0x02,0x40,0x7c,0x70,0x3c,0x10,0x09,0x07,0x04,0x00,0xc0,0x60,0xe0,0x70, 0x38,0x1c,0x0e,0x04,0x83,0x81,0xc0,0x70,0x70,0x38,0x1c,0x07,0x02,0xc1,0xc0,0x90, 0x00,0x0c,0x00,0x04,0x86,0x43,0x69,0xb0,0x30,0x18,0x06,0x07,0x01,0x00,0x00,0x00, 0x00,0x0c,0x63,0x16,0x00,0xc0,0x61,0x62,0x01,0x80,0x06,0x63,0x31,0x80,0x00,0x00, 0x60,0x00,0xc0,0x06,0x43,0x16,0x19,0x8c,0x06,0x33,0x01,0x80,0xc0,0x63,0x0c,0x01, 0x8c,0x86,0x07,0x39,0xc5,0x86,0x63,0x61,0x99,0x8c,0x01,0x83,0x1b,0x0d,0xb6,0x63, 0x31,0x01,0x86,0x03,0x00,0x30,0x30,0x00,0x1c,0x3e,0x1b,0x03,0xc1,0xf0,0xf0,0x60, 0x3e,0x6e,0x3e,0x0f,0x8c,0x60,0xc5,0xb1,0xb8,0x38,0x6c,0x0f,0x8c,0xc7,0xc1,0x83, 0x19,0x8d,0x82,0x63,0x31,0x9f,0xc1,0x80,0xc0,0xc0,0x00,0xaa,0x86,0xc0,0x47,0xe3, 0xf1,0xf8,0xfd,0xbf,0x83,0x8f,0xc3,0xef,0xf6,0xf8,0xfc,0xff,0x3f,0x9f,0x1f,0x8f, 0xc7,0xe3,0xf1,0xfb,0x7c,0x7e,0x3f,0x8f,0x8f,0xc7,0xe3,0xf8,0xfd,0x3e,0x3f,0x6f, 0x00,0x0c,0x0d,0x43,0x03,0xe1,0x88,0x30,0xc0,0x00,0x27,0x41,0x80,0x00,0x00,0x01, 0x72,0x00,0x22,0x04,0x01,0x80,0xc0,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xc0,0x04, 0x82,0x43,0x20,0x18,0x2c,0x16,0x0b,0x05,0x82,0xc1,0x60,0xb0,0xc0,0x30,0x18,0x0c, 0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x38,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x00,0xc7, 0x31,0x98,0xcc,0x66,0x33,0x11,0xf8,0xc8,0x7c,0x3e,0x1f,0x0f,0x87,0xc3,0xe1,0xd8, 0x3c,0x1e,0x0f,0x07,0x83,0xc7,0xc3,0xe1,0xf0,0xf8,0x06,0x37,0x07,0x03,0x81,0xc0, 0xe0,0x70,0x10,0x1d,0x31,0x98,0xcc,0x66,0x33,0x19,0xb0,0xc6,0x8f,0x7f,0x87,0x03, 0x81,0x80,0x90,0x30,0x6c,0x48,0x24,0x10,0x06,0x04,0x04,0x80,0x20,0x10,0x10,0x0e, 0x07,0x03,0x81,0xc0,0x60,0x88,0x38,0x0c,0x40,0x09,0x03,0x84,0x02,0x41,0x40,0x90, 0x00,0x0c,0x00,0x1f,0xe7,0x41,0xd1,0xa0,0x00,0x30,0x03,0x0a,0x81,0x00,0x00,0x00, 0x00,0x18,0x63,0x06,0x00,0xc0,0xc2,0x62,0x01,0xb0,0x0c,0x72,0x31,0x86,0x03,0x00, 0xc0,0x00,0x60,0x06,0x8f,0x16,0x19,0x0c,0x06,0x33,0x01,0x80,0xc0,0x63,0x0c,0x01, 0x8d,0x06,0x07,0x39,0x65,0x86,0x63,0x61,0x99,0x0e,0x01,0x83,0x19,0x89,0xb6,0x32, 0x33,0x03,0x06,0x01,0x80,0x30,0x78,0x00,0x00,0x03,0x1d,0x86,0x23,0x31,0x99,0xfc, 0x66,0x77,0x06,0x01,0x8c,0x40,0xc6,0xd9,0xdc,0x6c,0x76,0x19,0x8d,0xcc,0x27,0xf3, 0x19,0x8d,0x82,0x63,0x31,0x80,0xc0,0x80,0xc0,0x80,0x01,0x54,0x8c,0xc0,0x78,0xfc, 0x7e,0x7f,0x6f,0xcf,0x93,0xb7,0xdb,0xef,0xf9,0xfb,0xff,0xff,0xdf,0xef,0xef,0xf1, 0xf8,0xfc,0x7e,0x3f,0x9f,0x77,0xc7,0xf3,0xbf,0xf6,0xfc,0x7b,0xfd,0xbe,0xbf,0x6f, 0xff,0x0c,0x19,0x03,0x03,0x61,0x98,0x30,0x78,0x00,0x28,0x4f,0x83,0x30,0x00,0x01, 0x4a,0x00,0x1c,0x04,0x03,0x03,0x80,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xd9,0x84, 0x82,0x40,0xa0,0x18,0x2c,0x16,0x0b,0x05,0x82,0xc1,0x60,0xb0,0xc0,0x30,0x18,0x0c, 0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x2c,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x64,0xcb, 0x31,0x98,0xcc,0x66,0x33,0x31,0x8c,0xd8,0x06,0x03,0x01,0x80,0xc0,0x60,0x30,0x6c, 0x62,0x33,0x19,0x8c,0xc6,0x60,0xc0,0x60,0x30,0x18,0x1e,0x3b,0x8d,0x86,0xc3,0x61, 0xb0,0xd8,0x10,0x36,0x31,0x98,0xcc,0x66,0x33,0x19,0xd8,0xc6,0x0f,0x7f,0x82,0x01, 0x02,0x40,0xd0,0x40,0x6c,0x70,0x24,0x1c,0x06,0x04,0x03,0x01,0xc0,0xe0,0x10,0x12, 0x09,0x04,0x82,0x40,0x90,0x50,0x10,0x12,0x70,0x09,0x04,0x04,0x01,0xc1,0x20,0x60, 0x00,0x0c,0x00,0x04,0x83,0xc0,0x20,0xcc,0x00,0x30,0x03,0x02,0x01,0x00,0x00,0x00, 0x00,0x18,0x63,0x06,0x01,0x83,0x84,0x63,0xf1,0xd8,0x18,0x3c,0x31,0x86,0x03,0x01, 0x83,0xf8,0x30,0x1c,0x9b,0x33,0x1e,0x0c,0x06,0x33,0xe1,0x80,0xc0,0x7f,0x0c,0x01, 0x8f,0x06,0x07,0x79,0x65,0x86,0x66,0x61,0x9e,0x07,0x81,0x83,0x19,0x89,0xb6,0x1c, 0x1a,0x03,0x06,0x01,0x80,0x30,0x48,0x00,0x00,0x03,0x18,0xcc,0x06,0x33,0x18,0x60, 0xc6,0x63,0x06,0x01,0x8c,0x80,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8e,0x4c,0x01,0x83, 0x19,0x8d,0x92,0x32,0x31,0x81,0x87,0x00,0xc0,0x70,0xe4,0xaa,0x98,0xc0,0x7d,0xfe, 0xfd,0xbf,0x2f,0xbf,0x93,0x8f,0xdb,0xe3,0xf9,0xfb,0xff,0x1e,0x3f,0x1f,0xef,0xed, 0xf6,0xfb,0x7d,0xbf,0x6f,0xaf,0xef,0xed,0x8f,0xf6,0xfb,0xfb,0xfe,0x3e,0xdf,0x9f, 0x00,0x00,0x19,0x0f,0xc6,0x30,0xd0,0x00,0xcc,0x00,0x28,0x59,0x86,0x67,0xf0,0x01, 0x72,0x00,0x00,0x3f,0x86,0x00,0xc0,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xcc,0xc5, 0x32,0x83,0x4c,0x00,0x66,0x33,0x19,0x8c,0xc6,0x63,0x31,0xbc,0xc0,0x3e,0x1f,0x0f, 0x87,0xc1,0x80,0xc0,0x60,0x30,0xfb,0x2c,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x38,0xcb, 0x31,0x98,0xcc,0x66,0x31,0xa1,0x8c,0xcc,0x06,0x03,0x01,0x80,0xc0,0x60,0x30,0x6c, 0xc0,0x63,0x31,0x98,0xcc,0x60,0xc0,0x60,0x30,0x18,0x37,0x31,0x98,0xcc,0x66,0x33, 0x19,0x8c,0x00,0x67,0x31,0x98,0xcc,0x66,0x33,0x19,0x8c,0xc6,0x1f,0x7f,0x82,0x01, 0x02,0x40,0xb0,0x40,0x6c,0x07,0x03,0x83,0x80,0xe0,0xe0,0x00,0x18,0x0e,0x10,0x10, 0x08,0x04,0x02,0x00,0xf0,0x20,0x10,0x1e,0x08,0x89,0x03,0x00,0xe0,0x38,0x1c,0x0e, 0x00,0x0c,0x00,0x04,0x81,0xe0,0x41,0x6c,0x00,0x30,0x03,0x00,0x0f,0xe0,0x03,0xf8, 0x00,0x30,0x63,0x06,0x03,0x00,0xc7,0xf0,0x39,0x8c,0x30,0x3e,0x1b,0x80,0x00,0x03, 0x00,0x00,0x18,0x30,0x9b,0x23,0x19,0x0c,0x06,0x33,0x01,0xf8,0xc6,0x63,0x0c,0x01, 0x8d,0x86,0x05,0xd9,0x35,0x86,0x7c,0x61,0x9b,0x01,0xc1,0x83,0x19,0x99,0xb4,0x1c, 0x0c,0x06,0x06,0x00,0xc0,0x30,0xcc,0x00,0x00,0x3f,0x18,0xcc,0x06,0x33,0xf8,0x60, 0xc6,0x63,0x06,0x01,0x8f,0x00,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x0f,0x81,0x83, 0x18,0xd9,0xba,0x1c,0x1b,0x03,0x00,0x80,0xc0,0x81,0x75,0x54,0x98,0xc0,0x7d,0xfe, 0xfd,0xbf,0x4f,0xbf,0x93,0xf8,0xfc,0x7c,0x7f,0x1f,0x1f,0x6f,0xe7,0xf1,0xef,0xef, 0xf7,0xfb,0xfd,0xff,0x0f,0xdf,0xef,0xe1,0xf7,0x76,0xfc,0xff,0x1f,0xc7,0xe3,0xf1, 0xff,0x08,0x19,0x03,0x06,0x31,0xf8,0x00,0xc6,0x00,0x28,0x5b,0x8c,0xc0,0x11,0xf1, 0x4a,0x00,0x00,0x04,0x0c,0x00,0xc0,0x03,0x18,0x74,0x38,0x00,0x0c,0x18,0xc6,0x65, 0x52,0xb8,0x54,0x18,0x46,0x23,0x11,0x88,0xc4,0x62,0x31,0x30,0xc0,0x30,0x18,0x0c, 0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x26,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x10,0xd3, 0x31,0x98,0xcc,0x66,0x30,0xc1,0x8c,0xc6,0x7e,0x3f,0x1f,0x8f,0xc7,0xe3,0xf1,0xfc, 0xc0,0x7f,0x3f,0x9f,0xcf,0xe0,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33, 0x19,0x8c,0xfe,0x6b,0x31,0x98,0xcc,0x66,0x31,0xb1,0x8c,0x6c,0x0e,0x7f,0x82,0x01, 0x01,0x80,0x90,0x30,0xc6,0x08,0x01,0x02,0x00,0x40,0x80,0xe0,0x24,0x04,0x1c,0x10, 0x08,0x04,0x02,0x00,0x90,0x20,0x10,0x12,0x0d,0x86,0x00,0x81,0x00,0x40,0x20,0x10, 0x00,0x04,0x00,0x1f,0xe1,0x70,0xbb,0x28,0x00,0x30,0x03,0x00,0x01,0x00,0x00,0x00, 0x00,0x30,0x63,0x06,0x06,0x00,0x67,0xf0,0x19,0x8c,0x30,0x67,0x0d,0x80,0x00,0x01, 0x83,0xf8,0x30,0x30,0x9b,0x7f,0x19,0x8c,0x06,0x33,0x01,0x80,0xc6,0x63,0x0c,0x01, 0x8c,0xc6,0x05,0xd9,0x35,0x86,0x60,0x61,0x99,0x80,0xe1,0x83,0x18,0xd0,0xdc,0x26, 0x0c,0x0c,0x06,0x00,0xc0,0x30,0x84,0x00,0x00,0x63,0x18,0xcc,0x06,0x33,0x00,0x60, 0xc6,0x63,0x06,0x01,0x8d,0x80,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x03,0xe1,0x83, 0x18,0xd9,0xba,0x1c,0x1b,0x06,0x01,0x80,0xc0,0xc1,0x38,0xaa,0x80,0xc0,0x7d,0xfe, 0xfe,0x7f,0x6f,0xcf,0x39,0xf7,0xfe,0xfd,0xff,0xbf,0x7f,0x0f,0xdb,0xfb,0xe3,0xef, 0xf7,0xfb,0xfd,0xff,0x6f,0xdf,0xef,0xed,0xf2,0x79,0xff,0x7e,0xff,0xbf,0xdf,0xef, 0x00,0x0c,0x19,0x03,0x03,0x60,0x60,0x30,0x66,0x00,0x28,0x4d,0xc6,0x60,0x10,0x00, 0x84,0x00,0x00,0x04,0x0f,0x87,0x80,0x03,0x18,0x14,0x38,0x00,0x3f,0x0f,0x8c,0xc2, 0x90,0x84,0xa4,0x18,0xfe,0x7f,0x3f,0x9f,0xcf,0xe7,0xf1,0xf0,0xc0,0x30,0x18,0x0c, 0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x26,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x38,0xd3, 0x31,0x98,0xcc,0x66,0x30,0xc1,0x98,0xc6,0xc6,0x63,0x31,0x98,0xcc,0x66,0x33,0x60, 0xc0,0x60,0x30,0x18,0x0c,0x00,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33, 0x19,0x8c,0x00,0x6b,0x31,0x98,0xcc,0x66,0x31,0xb1,0x8c,0x6c,0x1c,0x7f,0x81,0x20, 0x90,0x38,0x18,0x0b,0x83,0x06,0x01,0x03,0x80,0x40,0xe0,0x90,0x24,0x04,0x03,0x8e, 0x86,0xc3,0x61,0x90,0x24,0x12,0x0e,0x04,0x8a,0x81,0xc7,0x70,0xc0,0x30,0x18,0x0c, 0x00,0x00,0x00,0x04,0x81,0x31,0x6f,0x30,0x00,0x18,0x06,0x00,0x01,0x00,0x00,0x00, 0x00,0x60,0x63,0x06,0x0c,0x00,0x60,0x60,0x19,0x8c,0x60,0x63,0x01,0x80,0x00,0x00, 0xc0,0x00,0x60,0x00,0x4d,0xe1,0x99,0x8c,0x06,0x33,0x01,0x80,0xc6,0x63,0x0c,0x01, 0x8c,0xc6,0x04,0x99,0x1d,0x86,0x60,0x61,0x99,0x80,0x61,0x83,0x18,0xd0,0xdc,0x63, 0x0c,0x0c,0x06,0x00,0x60,0x30,0x84,0x00,0x00,0x63,0x18,0xcc,0x06,0x33,0x00,0x60, 0x6e,0x63,0x06,0x01,0x8c,0xc0,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x00,0x61,0x83, 0x18,0xd0,0xcc,0x26,0x0e,0x0c,0x03,0x00,0xc0,0x60,0x01,0x54,0x98,0xc0,0x7e,0xdf, 0x6f,0xc7,0xe7,0xf4,0x7c,0xf9,0xfe,0xfc,0x7f,0xbf,0x1f,0x5f,0xdb,0xfb,0xfc,0x71, 0x79,0x3c,0x9e,0x6f,0xdb,0xed,0xf1,0xfb,0x75,0x7e,0x38,0x8f,0x3f,0xcf,0xe7,0xf3, 0xff,0x0c,0x0d,0x03,0x03,0xe1,0xf8,0x30,0x3c,0x00,0x27,0x40,0x03,0x30,0x00,0x00, 0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x18,0x14,0x00,0x00,0x00,0x00,0x19,0x82, 0xf8,0x98,0xbe,0x70,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x30,0xc0,0x30,0x18,0x0c, 0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x23,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x4c,0xe3, 0x31,0x98,0xcc,0x66,0x30,0xc1,0xf0,0xc6,0xc6,0x63,0x31,0x98,0xcc,0x66,0x33,0x60, 0xc0,0x60,0x30,0x18,0x0c,0x00,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33, 0x19,0x8c,0x10,0x73,0x31,0x98,0xcc,0x66,0x30,0xe1,0x8c,0x38,0x1c,0x7f,0x80,0xa0, 0x50,0x10,0x24,0x0d,0xff,0x01,0x01,0x02,0x00,0x40,0x80,0xf0,0x24,0x04,0x02,0x01, 0x81,0x20,0x10,0x30,0x28,0x1a,0x09,0x06,0x8a,0x81,0x20,0x90,0x20,0x08,0x04,0x02, 0x00,0x0c,0x00,0x04,0x85,0x32,0x6f,0xb8,0x00,0x18,0x06,0x00,0x01,0x01,0xc0,0x00, 0x70,0x60,0x36,0x06,0x1f,0xcc,0xe0,0x63,0x30,0xd8,0x60,0x63,0x33,0x06,0x03,0x00, 0x60,0x00,0xc0,0x30,0x60,0x61,0x99,0x86,0x66,0x63,0x01,0x80,0x66,0x63,0x0c,0x03, 0x0c,0x66,0x04,0x19,0x1c,0xcc,0x60,0x33,0x18,0xcc,0x61,0x81,0xb0,0x60,0xcc,0x63, 0x0c,0x18,0x06,0x00,0x60,0x30,0x00,0x00,0x00,0x67,0x19,0x86,0x23,0x71,0x88,0x60, 0x36,0x63,0x06,0x01,0x8c,0x60,0xc6,0xd9,0x8c,0x6c,0x66,0x1b,0x8c,0x08,0x61,0x83, 0xb8,0x70,0xcc,0x63,0x0c,0x18,0x03,0x00,0xc0,0x60,0x00,0xaa,0x98,0xc0,0x7f,0x5f, 0xaf,0xef,0xdb,0xf2,0x00,0xfe,0xfe,0xfd,0xff,0xbf,0x7f,0x6f,0xdb,0xfb,0xfd,0xfe, 0x7e,0xdf,0xef,0xcf,0xd7,0xe5,0xf6,0xf9,0x75,0x7e,0xdf,0x6f,0xdf,0xf7,0xfb,0xfd, 0x00,0x0c,0x07,0xc6,0x04,0x10,0x60,0x30,0x06,0x00,0x10,0x80,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x3f,0x80,0x00,0x00,0x03,0xb8,0x14,0x00,0x00,0x00,0x00,0x00,0x04, 0x11,0x21,0x04,0xc0,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x30,0x66,0x30,0x18,0x0c, 0x06,0x01,0x80,0xc0,0x60,0x30,0x66,0x23,0x99,0x8c,0xc6,0x63,0x31,0x98,0x00,0x66, 0x1b,0x0d,0x86,0xc3,0x60,0xc1,0x80,0xc6,0xce,0x67,0x33,0x99,0xcc,0xe6,0x73,0x74, 0x62,0x31,0x18,0x8c,0x46,0x20,0xc0,0x60,0x30,0x18,0x36,0x31,0x8d,0x86,0xc3,0x61, 0xb0,0xd8,0x10,0x36,0x3b,0x9d,0xce,0xe7,0x70,0xc1,0x98,0x30,0x00,0x7f,0x80,0xc0, 0x60,0x10,0x24,0x0c,0x38,0x0e,0x01,0x02,0x00,0x40,0x80,0xa0,0x18,0x0e,0x03,0x00, 0x80,0x40,0x60,0x50,0x30,0x16,0x0e,0x05,0x88,0x81,0xc0,0x81,0xc0,0x70,0x38,0x1c, 0x00,0x0c,0x00,0x04,0x83,0xe0,0x39,0xcc,0x00,0x0c,0x0c,0x00,0x00,0x01,0xc0,0x00, 0x70,0xc0,0x1c,0x06,0x1f,0xc7,0xc0,0x61,0xe0,0x70,0x60,0x3e,0x1e,0x06,0x03,0x00, 0x00,0x00,0x00,0x30,0x1e,0x61,0x9f,0x03,0xc7,0xc3,0xf1,0x80,0x3e,0x63,0x3f,0x1e, 0x0c,0x67,0xe4,0x19,0x0c,0x78,0x60,0x1e,0x18,0xc7,0xc1,0x80,0xe0,0x60,0xcc,0x63, 0x0c,0x1f,0xc6,0x00,0x30,0x30,0x00,0x00,0x00,0x3b,0x9f,0x03,0xc1,0xb0,0xf0,0x60, 0x06,0x63,0x06,0x01,0x8c,0x70,0xc6,0xd9,0x8c,0x38,0x7c,0x0d,0x8c,0x07,0xc0,0xf1, 0xd8,0x60,0xcc,0x63,0x0c,0x1f,0xc3,0x00,0xc0,0x60,0x01,0x54,0x80,0xc0,0x7f,0x3f, 0x9f,0xef,0xdb,0xf3,0xc7,0xf1,0xfe,0xfd,0xff,0xbf,0x7f,0xff,0xe7,0xf1,0xfc,0xff, 0x7f,0xbf,0x9f,0xaf,0xcf,0xe9,0xf1,0xfa,0x77,0x7e,0x3f,0x7e,0x3f,0x8f,0xc7,0xe3, 0xff,0x0c,0x01,0x0f,0xe8,0x08,0x60,0x30,0xc6,0x00,0x0f,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xd8,0x14,0x00,0x00,0x00,0x00,0x00,0x04, 0x11,0x3d,0x04,0xc0,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x3c,0x3c,0x3f,0x1f,0x8f, 0xc7,0xe7,0xe3,0xf1,0xf8,0xfc,0x7c,0x21,0x8f,0x07,0x83,0xc1,0xe0,0xf0,0x00,0xbc, 0x0e,0x07,0x03,0x81,0xc0,0xc1,0x80,0xcc,0x77,0x3b,0x9d,0xce,0xe7,0x73,0xb9,0x98, 0x3c,0x1e,0x0f,0x07,0x83,0xc0,0xc0,0x60,0x30,0x18,0x1c,0x31,0x87,0x03,0x81,0xc0, 0xe0,0x70,0x00,0x5c,0x1d,0x8e,0xc7,0x63,0xb0,0xc1,0xf0,0x30,0x00,0x7f,0x81,0x40, 0xa0,0x10,0x28,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0x00,0x02,0x00, 0x80,0x80,0x10,0xf8,0x28,0x12,0x09,0x04,0x80,0x01,0x20,0x80,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x06,0x18,0x00,0x00,0x00,0x40,0x00, 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x07,0xc0,0x31,0xf0,0x01,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xcc,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x80,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x18,0x00,0x01,0xe0,0xc3,0xc0,0x00,0x00,0xff,0xc0,0x7e,0xbf, 0x5f,0xef,0xd7,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff, 0x7f,0x7f,0xef,0x07,0xd7,0xed,0xf6,0xfb,0x7f,0xfe,0xdf,0x7f,0xff,0xff,0xff,0xff, 0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x30,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x14,0x00,0x08,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x81,0x80,0x60,0x00,0x7f,0x81,0x20, 0x90,0x10,0x1c,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80, 0x81,0xe0,0x60,0x10,0x24,0x12,0x0e,0x04,0x80,0x01,0xc0,0x70,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x78,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x80,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xfe,0xdf, 0x6f,0xef,0xe3,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x7f, 0x7e,0x1f,0x9f,0xef,0xdb,0xed,0xf1,0xfb,0x7f,0xfe,0x3f,0x8f,0xff,0xff,0xff,0xff, 0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x81,0x80,0x60,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x32,0x35,0x36,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x31,0x35,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x33,0x20, 0x00,0x00,0x01,0x0c,0x00,0x09,0x09,0x00,0x01,0x0f,0x00,0x09,0x12,0x00,0x01,0x0f, 0x00,0x09,0x1b,0x00,0x01,0x0f,0x00,0x09,0x24,0x00,0x01,0x0f,0x00,0x09,0x2d,0x00, 0x01,0x0f,0x00,0x09,0x36,0x00,0x01,0x0f,0x00,0x09,0x3f,0x00,0x03,0x0d,0x00,0x09, 0x48,0x00,0x03,0x0d,0x00,0x09,0x51,0x00,0x03,0x0d,0x00,0x09,0x5a,0x00,0x03,0x0d, 0x00,0x09,0x63,0x00,0x03,0x0d,0x00,0x09,0x6c,0x00,0x03,0x0d,0x00,0x09,0x75,0x00, 0x03,0x0e,0x00,0x09,0x7e,0x00,0x03,0x0d,0x00,0x09,0x87,0x00,0x03,0x0d,0x00,0x09, 0x90,0x00,0x01,0x0f,0x00,0x09,0x99,0x00,0x01,0x0f,0x00,0x09,0xa2,0x00,0x01,0x0f, 0x00,0x09,0xab,0x00,0x01,0x0f,0x00,0x09,0xb4,0x00,0x01,0x0f,0x00,0x09,0xbd,0x00, 0x01,0x0f,0x00,0x09,0xc6,0x00,0x01,0x0f,0x00,0x09,0xcf,0x00,0x01,0x0f,0x00,0x09, 0xd8,0x00,0x01,0x0f,0x00,0x09,0xe1,0x00,0x03,0x0d,0x00,0x09,0xea,0x00,0x01,0x0f, 0x00,0x09,0xf3,0x00,0x01,0x0f,0x00,0x09,0xfc,0x00,0x03,0x0d,0x00,0x09,0x05,0x01, 0x03,0x0d,0x00,0x09,0x0e,0x01,0x03,0x0d,0x00,0x09,0x17,0x01,0x03,0x0d,0x00,0x09, 0x20,0x01,0x00,0x00,0x00,0x09,0x29,0x01,0x03,0x0d,0x00,0x09,0x32,0x01,0x02,0x05, 0x00,0x09,0x3b,0x01,0x03,0x0d,0x00,0x09,0x44,0x01,0x02,0x0e,0x00,0x09,0x4d,0x01, 0x03,0x0d,0x00,0x09,0x56,0x01,0x03,0x0d,0x00,0x09,0x5f,0x01,0x02,0x06,0x00,0x09, 0x68,0x01,0x02,0x0e,0x00,0x09,0x71,0x01,0x02,0x0e,0x00,0x09,0x7a,0x01,0x03,0x08, 0x00,0x09,0x83,0x01,0x05,0x0c,0x00,0x09,0x8c,0x01,0x0b,0x0f,0x00,0x09,0x95,0x01, 0x08,0x09,0x00,0x09,0x9e,0x01,0x0b,0x0d,0x00,0x09,0xa7,0x01,0x02,0x0e,0x00,0x09, 0xb0,0x01,0x03,0x0d,0x00,0x09,0xb9,0x01,0x03,0x0d,0x00,0x09,0xc2,0x01,0x03,0x0d, 0x00,0x09,0xcb,0x01,0x03,0x0d,0x00,0x09,0xd4,0x01,0x03,0x0d,0x00,0x09,0xdd,0x01, 0x03,0x0d,0x00,0x09,0xe6,0x01,0x03,0x0d,0x00,0x09,0xef,0x01,0x03,0x0d,0x00,0x09, 0xf8,0x01,0x03,0x0d,0x00,0x09,0x01,0x02,0x03,0x0d,0x00,0x09,0x0a,0x02,0x06,0x0d, 0x00,0x09,0x13,0x02,0x06,0x0f,0x00,0x09,0x1c,0x02,0x05,0x0c,0x00,0x09,0x25,0x02, 0x07,0x0a,0x00,0x09,0x2e,0x02,0x05,0x0c,0x00,0x09,0x37,0x02,0x03,0x0d,0x00,0x09, 0x40,0x02,0x03,0x0d,0x00,0x09,0x49,0x02,0x03,0x0d,0x00,0x09,0x52,0x02,0x03,0x0d, 0x00,0x09,0x5b,0x02,0x03,0x0d,0x00,0x09,0x64,0x02,0x03,0x0d,0x00,0x09,0x6d,0x02, 0x03,0x0d,0x00,0x09,0x76,0x02,0x03,0x0d,0x00,0x09,0x7f,0x02,0x03,0x0d,0x00,0x09, 0x88,0x02,0x03,0x0d,0x00,0x09,0x91,0x02,0x03,0x0d,0x00,0x09,0x9a,0x02,0x03,0x0d, 0x00,0x09,0xa3,0x02,0x03,0x0d,0x00,0x09,0xac,0x02,0x03,0x0d,0x00,0x09,0xb5,0x02, 0x03,0x0d,0x00,0x09,0xbe,0x02,0x03,0x0d,0x00,0x09,0xc7,0x02,0x03,0x0d,0x00,0x09, 0xd0,0x02,0x03,0x0d,0x00,0x09,0xd9,0x02,0x03,0x0f,0x00,0x09,0xe2,0x02,0x03,0x0d, 0x00,0x09,0xeb,0x02,0x03,0x0d,0x00,0x09,0xf4,0x02,0x03,0x0d,0x00,0x09,0xfd,0x02, 0x03,0x0d,0x00,0x09,0x06,0x03,0x03,0x0d,0x00,0x09,0x0f,0x03,0x03,0x0d,0x00,0x09, 0x18,0x03,0x03,0x0d,0x00,0x09,0x21,0x03,0x03,0x0d,0x00,0x09,0x2a,0x03,0x03,0x0d, 0x00,0x09,0x33,0x03,0x02,0x0e,0x00,0x09,0x3c,0x03,0x02,0x0e,0x00,0x09,0x45,0x03, 0x02,0x0e,0x00,0x09,0x4e,0x03,0x04,0x0b,0x00,0x09,0x57,0x03,0x0d,0x0e,0x00,0x09, 0x60,0x03,0x02,0x06,0x00,0x09,0x69,0x03,0x05,0x0d,0x00,0x09,0x72,0x03,0x02,0x0d, 0x00,0x09,0x7b,0x03,0x05,0x0d,0x00,0x09,0x84,0x03,0x02,0x0d,0x00,0x09,0x8d,0x03, 0x05,0x0d,0x00,0x09,0x96,0x03,0x02,0x0d,0x00,0x09,0x9f,0x03,0x05,0x0f,0x00,0x09, 0xa8,0x03,0x02,0x0d,0x00,0x09,0xb1,0x03,0x02,0x0d,0x00,0x09,0xba,0x03,0x02,0x0f, 0x00,0x09,0xc3,0x03,0x02,0x0d,0x00,0x09,0xcc,0x03,0x02,0x0d,0x00,0x09,0xd5,0x03, 0x05,0x0d,0x00,0x09,0xde,0x03,0x05,0x0d,0x00,0x09,0xe7,0x03,0x05,0x0d,0x00,0x09, 0xf0,0x03,0x05,0x0f,0x00,0x09,0xf9,0x03,0x05,0x0f,0x00,0x09,0x02,0x04,0x05,0x0d, 0x00,0x09,0x0b,0x04,0x05,0x0d,0x00,0x09,0x14,0x04,0x03,0x0d,0x00,0x09,0x1d,0x04, 0x05,0x0d,0x00,0x09,0x26,0x04,0x05,0x0d,0x00,0x09,0x2f,0x04,0x05,0x0d,0x00,0x09, 0x38,0x04,0x05,0x0d,0x00,0x09,0x41,0x04,0x05,0x0f,0x00,0x09,0x4a,0x04,0x05,0x0d, 0x00,0x09,0x53,0x04,0x02,0x0e,0x00,0x09,0x5c,0x04,0x02,0x0e,0x00,0x09,0x65,0x04, 0x02,0x0e,0x00,0x09,0x6e,0x04,0x07,0x0a,0x00,0x09,0x77,0x04,0x01,0x0d,0x00,0x09, 0x80,0x04,0x00,0x0e,0x00,0x09,0x89,0x04,0x00,0x0f,0x00,0x09,0x92,0x04,0x00,0x0f, 0x00,0x09,0x9b,0x04,0x00,0x0f,0x00,0x09,0xa4,0x04,0x00,0x0f,0x00,0x09,0xad,0x04, 0x00,0x0f,0x00,0x09,0xb6,0x04,0x00,0x0f,0x00,0x09,0xbf,0x04,0x00,0x0f,0x00,0x09, 0xc8,0x04,0x00,0x0f,0x00,0x09,0xd1,0x04,0x00,0x0f,0x00,0x09,0xda,0x04,0x00,0x0f, 0x00,0x09,0xe3,0x04,0x00,0x0f,0x00,0x09,0xec,0x04,0x00,0x0f,0x00,0x09,0xf5,0x04, 0x00,0x0f,0x00,0x09,0xfe,0x04,0x00,0x0f,0x00,0x09,0x07,0x05,0x00,0x0f,0x00,0x09, 0x10,0x05,0x00,0x0f,0x00,0x09,0x19,0x05,0x00,0x0f,0x00,0x09,0x22,0x05,0x00,0x0f, 0x00,0x09,0x2b,0x05,0x00,0x0f,0x00,0x09,0x34,0x05,0x00,0x0f,0x00,0x09,0x3d,0x05, 0x00,0x0f,0x00,0x09,0x46,0x05,0x00,0x0f,0x00,0x09,0x4f,0x05,0x00,0x0f,0x00,0x09, 0x58,0x05,0x00,0x0f,0x00,0x09,0x61,0x05,0x00,0x0f,0x00,0x09,0x6a,0x05,0x00,0x0f, 0x00,0x09,0x73,0x05,0x00,0x0f,0x00,0x09,0x7c,0x05,0x00,0x0f,0x00,0x09,0x85,0x05, 0x00,0x0f,0x00,0x09,0x8e,0x05,0x00,0x0f,0x00,0x09,0x97,0x05,0x00,0x0f,0x00,0x09, 0xa0,0x05,0x00,0x0d,0x00,0x09,0xa9,0x05,0x05,0x0f,0x00,0x09,0xb2,0x05,0x02,0x0e, 0x00,0x09,0xbb,0x05,0x03,0x0d,0x00,0x09,0xc4,0x05,0x03,0x0d,0x00,0x09,0xcd,0x05, 0x03,0x0d,0x00,0x09,0xd6,0x05,0x02,0x0e,0x00,0x09,0xdf,0x05,0x03,0x0e,0x00,0x09, 0xe8,0x05,0x02,0x04,0x00,0x09,0xf1,0x05,0x03,0x0d,0x00,0x09,0xfa,0x05,0x03,0x0a, 0x00,0x09,0x03,0x06,0x06,0x0b,0x00,0x09,0x0c,0x06,0x07,0x0a,0x00,0x09,0x15,0x06, 0x08,0x09,0x00,0x09,0x1e,0x06,0x03,0x0b,0x00,0x09,0x27,0x06,0x02,0x03,0x00,0x09, 0x30,0x06,0x03,0x07,0x00,0x09,0x39,0x06,0x05,0x0c,0x00,0x09,0x42,0x06,0x03,0x0a, 0x00,0x09,0x4b,0x06,0x03,0x0a,0x00,0x09,0x54,0x06,0x02,0x04,0x00,0x09,0x5d,0x06, 0x05,0x0f,0x00,0x09,0x66,0x06,0x03,0x0e,0x00,0x09,0x6f,0x06,0x08,0x0a,0x00,0x09, 0x78,0x06,0x0d,0x0f,0x00,0x09,0x81,0x06,0x03,0x0a,0x00,0x09,0x8a,0x06,0x03,0x0a, 0x00,0x09,0x93,0x06,0x06,0x0b,0x00,0x09,0x9c,0x06,0x03,0x0d,0x00,0x09,0xa5,0x06, 0x03,0x0d,0x00,0x09,0xae,0x06,0x03,0x0d,0x00,0x09,0xb7,0x06,0x05,0x0f,0x00,0x09, 0xc0,0x06,0x00,0x0d,0x00,0x09,0xc9,0x06,0x00,0x0d,0x00,0x09,0xd2,0x06,0x00,0x0d, 0x00,0x09,0xdb,0x06,0x00,0x0d,0x00,0x09,0xe4,0x06,0x00,0x0d,0x00,0x09,0xed,0x06, 0x01,0x0d,0x00,0x09,0xf6,0x06,0x03,0x0d,0x00,0x09,0xff,0x06,0x03,0x0f,0x00,0x09, 0x08,0x07,0x00,0x0d,0x00,0x09,0x11,0x07,0x00,0x0d,0x00,0x09,0x1a,0x07,0x00,0x0d, 0x00,0x09,0x23,0x07,0x00,0x0d,0x00,0x09,0x2c,0x07,0x00,0x0d,0x00,0x09,0x35,0x07, 0x00,0x0d,0x00,0x09,0x3e,0x07,0x00,0x0d,0x00,0x09,0x47,0x07,0x00,0x0d,0x00,0x09, 0x50,0x07,0x03,0x0d,0x00,0x09,0x59,0x07,0x00,0x0d,0x00,0x09,0x62,0x07,0x00,0x0d, 0x00,0x09,0x6b,0x07,0x00,0x0d,0x00,0x09,0x74,0x07,0x00,0x0d,0x00,0x09,0x7d,0x07, 0x00,0x0d,0x00,0x09,0x86,0x07,0x00,0x0d,0x00,0x09,0x8f,0x07,0x06,0x0b,0x00,0x09, 0x98,0x07,0x03,0x0d,0x00,0x09,0xa1,0x07,0x00,0x0d,0x00,0x09,0xaa,0x07,0x00,0x0d, 0x00,0x09,0xb3,0x07,0x00,0x0d,0x00,0x09,0xbc,0x07,0x00,0x0d,0x00,0x09,0xc5,0x07, 0x00,0x0d,0x00,0x09,0xce,0x07,0x03,0x0d,0x00,0x09,0xd7,0x07,0x02,0x0d,0x00,0x09, 0xe0,0x07,0x02,0x0d,0x00,0x09,0xe9,0x07,0x02,0x0d,0x00,0x09,0xf2,0x07,0x02,0x0d, 0x00,0x09,0xfb,0x07,0x02,0x0d,0x00,0x09,0x04,0x08,0x02,0x0d,0x00,0x09,0x0d,0x08, 0x02,0x0d,0x00,0x09,0x16,0x08,0x05,0x0d,0x00,0x09,0x1f,0x08,0x05,0x0f,0x00,0x09, 0x28,0x08,0x02,0x0d,0x00,0x09,0x31,0x08,0x02,0x0d,0x00,0x09,0x3a,0x08,0x02,0x0d, 0x00,0x09,0x43,0x08,0x02,0x0d,0x00,0x09,0x4c,0x08,0x02,0x0d,0x00,0x09,0x55,0x08, 0x02,0x0d,0x00,0x09,0x5e,0x08,0x02,0x0d,0x00,0x09,0x67,0x08,0x02,0x0d,0x00,0x09, 0x70,0x08,0x02,0x0d,0x00,0x09,0x79,0x08,0x02,0x0d,0x00,0x09,0x82,0x08,0x02,0x0d, 0x00,0x09,0x8b,0x08,0x02,0x0d,0x00,0x09,0x94,0x08,0x02,0x0d,0x00,0x09,0x9d,0x08, 0x02,0x0d,0x00,0x09,0xa6,0x08,0x02,0x0d,0x00,0x09,0xaf,0x08,0x05,0x0c,0x00,0x09, 0xb8,0x08,0x05,0x0d,0x00,0x09,0xc1,0x08,0x02,0x0d,0x00,0x09,0xca,0x08,0x02,0x0d, 0x00,0x09,0xd3,0x08,0x02,0x0d,0x00,0x09,0xdc,0x08,0x02,0x0d,0x00,0x09,0xe5,0x08, 0x02,0x0f,0x00,0x09,0xee,0x08,0x03,0x0f,0x00,0x09,0xf7,0x08,0x02,0x0f,0x00,0x09, 0x00,0x09,0x00,0x00,0x00,0x00, }; int sizeofdefont = sizeof defontdata; void _unpackinfo(Fontchar *fc, uchar *p, int n) { int j; for(j=0; j<=n; j++){ fc->x = p[0]|(p[1]<<8); fc->top = p[2]; fc->bottom = p[3]; fc->left = p[4]; fc->width = p[5]; fc++; p += 6; } } drawterm-20170818/libdraw/drawrepl.c000066400000000000000000000004721314554504700172360ustar00rootroot00000000000000#include #include #include int drawreplxy(int min, int max, int x) { int sx; sx = (x-min)%(max-min); if(sx < 0) sx += max-min; return sx+min; } Point drawrepl(Rectangle r, Point p) { p.x = drawreplxy(r.min.x, r.max.x, p.x); p.y = drawreplxy(r.min.y, r.max.y, p.y); return p; } drawterm-20170818/libdraw/icossin.c000066400000000000000000000041051314554504700170620ustar00rootroot00000000000000#include #include #include /* * Integer sine and cosine for integral degree argument. * Tables computed by (sin,cos)(PI*d/180). */ static short sinus[91] = { 0, /* 0 */ 18, /* 1 */ 36, /* 2 */ 54, /* 3 */ 71, /* 4 */ 89, /* 5 */ 107, /* 6 */ 125, /* 7 */ 143, /* 8 */ 160, /* 9 */ 178, /* 10 */ 195, /* 11 */ 213, /* 12 */ 230, /* 13 */ 248, /* 14 */ 265, /* 15 */ 282, /* 16 */ 299, /* 17 */ 316, /* 18 */ 333, /* 19 */ 350, /* 20 */ 367, /* 21 */ 384, /* 22 */ 400, /* 23 */ 416, /* 24 */ 433, /* 25 */ 449, /* 26 */ 465, /* 27 */ 481, /* 28 */ 496, /* 29 */ 512, /* 30 */ 527, /* 31 */ 543, /* 32 */ 558, /* 33 */ 573, /* 34 */ 587, /* 35 */ 602, /* 36 */ 616, /* 37 */ 630, /* 38 */ 644, /* 39 */ 658, /* 40 */ 672, /* 41 */ 685, /* 42 */ 698, /* 43 */ 711, /* 44 */ 724, /* 45 */ 737, /* 46 */ 749, /* 47 */ 761, /* 48 */ 773, /* 49 */ 784, /* 50 */ 796, /* 51 */ 807, /* 52 */ 818, /* 53 */ 828, /* 54 */ 839, /* 55 */ 849, /* 56 */ 859, /* 57 */ 868, /* 58 */ 878, /* 59 */ 887, /* 60 */ 896, /* 61 */ 904, /* 62 */ 912, /* 63 */ 920, /* 64 */ 928, /* 65 */ 935, /* 66 */ 943, /* 67 */ 949, /* 68 */ 956, /* 69 */ 962, /* 70 */ 968, /* 71 */ 974, /* 72 */ 979, /* 73 */ 984, /* 74 */ 989, /* 75 */ 994, /* 76 */ 998, /* 77 */ 1002, /* 78 */ 1005, /* 79 */ 1008, /* 80 */ 1011, /* 81 */ 1014, /* 82 */ 1016, /* 83 */ 1018, /* 84 */ 1020, /* 85 */ 1022, /* 86 */ 1023, /* 87 */ 1023, /* 88 */ 1024, /* 89 */ 1024, /* 90 */ }; void icossin(int deg, int *cosp, int *sinp) { int sinsign, cossign; short *stp, *ctp; deg %= 360; if(deg < 0) deg += 360; sinsign = 1; cossign = 1; stp = 0; ctp = 0; switch(deg/90){ case 2: sinsign = -1; cossign = -1; deg -= 180; /* fall through */ case 0: stp = &sinus[deg]; ctp = &sinus[90-deg]; break; case 3: sinsign = -1; cossign = -1; deg -= 180; /* fall through */ case 1: deg = 180-deg; cossign = -cossign; stp = &sinus[deg]; ctp = &sinus[90-deg]; break; } *sinp = sinsign*stp[0]; *cosp = cossign*ctp[0]; } drawterm-20170818/libdraw/icossin2.c000066400000000000000000000107531314554504700171520ustar00rootroot00000000000000#include #include #include /* * Sine and Cosine of arctangents, calculated by * (sin(atan(index/100.0))*1024.+0.5) * (cos(atan(index/100.0))*1024.+0.5) * To use, get rational tangent between 0<=tan<=1, scale by 100, * and look up sin and cos, and use linear interpolation. divide by 1024. * Maximum error is 0.0020. Without linear interpolation, it's 0.010. */ static short sinus[] = { 0, /* 0.00 */ 10, /* 0.01 */ 20, /* 0.02 */ 31, /* 0.03 */ 41, /* 0.04 */ 51, /* 0.05 */ 61, /* 0.06 */ 72, /* 0.07 */ 82, /* 0.08 */ 92, /* 0.09 */ 102, /* 0.10 */ 112, /* 0.11 */ 122, /* 0.12 */ 132, /* 0.13 */ 142, /* 0.14 */ 152, /* 0.15 */ 162, /* 0.16 */ 172, /* 0.17 */ 181, /* 0.18 */ 191, /* 0.19 */ 201, /* 0.20 */ 210, /* 0.21 */ 220, /* 0.22 */ 230, /* 0.23 */ 239, /* 0.24 */ 248, /* 0.25 */ 258, /* 0.26 */ 267, /* 0.27 */ 276, /* 0.28 */ 285, /* 0.29 */ 294, /* 0.30 */ 303, /* 0.31 */ 312, /* 0.32 */ 321, /* 0.33 */ 330, /* 0.34 */ 338, /* 0.35 */ 347, /* 0.36 */ 355, /* 0.37 */ 364, /* 0.38 */ 372, /* 0.39 */ 380, /* 0.40 */ 388, /* 0.41 */ 397, /* 0.42 */ 405, /* 0.43 */ 412, /* 0.44 */ 420, /* 0.45 */ 428, /* 0.46 */ 436, /* 0.47 */ 443, /* 0.48 */ 451, /* 0.49 */ 458, /* 0.50 */ 465, /* 0.51 */ 472, /* 0.52 */ 480, /* 0.53 */ 487, /* 0.54 */ 493, /* 0.55 */ 500, /* 0.56 */ 507, /* 0.57 */ 514, /* 0.58 */ 520, /* 0.59 */ 527, /* 0.60 */ 533, /* 0.61 */ 540, /* 0.62 */ 546, /* 0.63 */ 552, /* 0.64 */ 558, /* 0.65 */ 564, /* 0.66 */ 570, /* 0.67 */ 576, /* 0.68 */ 582, /* 0.69 */ 587, /* 0.70 */ 593, /* 0.71 */ 598, /* 0.72 */ 604, /* 0.73 */ 609, /* 0.74 */ 614, /* 0.75 */ 620, /* 0.76 */ 625, /* 0.77 */ 630, /* 0.78 */ 635, /* 0.79 */ 640, /* 0.80 */ 645, /* 0.81 */ 649, /* 0.82 */ 654, /* 0.83 */ 659, /* 0.84 */ 663, /* 0.85 */ 668, /* 0.86 */ 672, /* 0.87 */ 676, /* 0.88 */ 681, /* 0.89 */ 685, /* 0.90 */ 689, /* 0.91 */ 693, /* 0.92 */ 697, /* 0.93 */ 701, /* 0.94 */ 705, /* 0.95 */ 709, /* 0.96 */ 713, /* 0.97 */ 717, /* 0.98 */ 720, /* 0.99 */ 724, /* 1.00 */ 728, /* 1.01 */ }; static short cosinus[] = { 1024, /* 0.00 */ 1024, /* 0.01 */ 1024, /* 0.02 */ 1024, /* 0.03 */ 1023, /* 0.04 */ 1023, /* 0.05 */ 1022, /* 0.06 */ 1022, /* 0.07 */ 1021, /* 0.08 */ 1020, /* 0.09 */ 1019, /* 0.10 */ 1018, /* 0.11 */ 1017, /* 0.12 */ 1015, /* 0.13 */ 1014, /* 0.14 */ 1013, /* 0.15 */ 1011, /* 0.16 */ 1010, /* 0.17 */ 1008, /* 0.18 */ 1006, /* 0.19 */ 1004, /* 0.20 */ 1002, /* 0.21 */ 1000, /* 0.22 */ 998, /* 0.23 */ 996, /* 0.24 */ 993, /* 0.25 */ 991, /* 0.26 */ 989, /* 0.27 */ 986, /* 0.28 */ 983, /* 0.29 */ 981, /* 0.30 */ 978, /* 0.31 */ 975, /* 0.32 */ 972, /* 0.33 */ 969, /* 0.34 */ 967, /* 0.35 */ 963, /* 0.36 */ 960, /* 0.37 */ 957, /* 0.38 */ 954, /* 0.39 */ 951, /* 0.40 */ 947, /* 0.41 */ 944, /* 0.42 */ 941, /* 0.43 */ 937, /* 0.44 */ 934, /* 0.45 */ 930, /* 0.46 */ 927, /* 0.47 */ 923, /* 0.48 */ 920, /* 0.49 */ 916, /* 0.50 */ 912, /* 0.51 */ 909, /* 0.52 */ 905, /* 0.53 */ 901, /* 0.54 */ 897, /* 0.55 */ 893, /* 0.56 */ 890, /* 0.57 */ 886, /* 0.58 */ 882, /* 0.59 */ 878, /* 0.60 */ 874, /* 0.61 */ 870, /* 0.62 */ 866, /* 0.63 */ 862, /* 0.64 */ 859, /* 0.65 */ 855, /* 0.66 */ 851, /* 0.67 */ 847, /* 0.68 */ 843, /* 0.69 */ 839, /* 0.70 */ 835, /* 0.71 */ 831, /* 0.72 */ 827, /* 0.73 */ 823, /* 0.74 */ 819, /* 0.75 */ 815, /* 0.76 */ 811, /* 0.77 */ 807, /* 0.78 */ 804, /* 0.79 */ 800, /* 0.80 */ 796, /* 0.81 */ 792, /* 0.82 */ 788, /* 0.83 */ 784, /* 0.84 */ 780, /* 0.85 */ 776, /* 0.86 */ 773, /* 0.87 */ 769, /* 0.88 */ 765, /* 0.89 */ 761, /* 0.90 */ 757, /* 0.91 */ 754, /* 0.92 */ 750, /* 0.93 */ 746, /* 0.94 */ 742, /* 0.95 */ 739, /* 0.96 */ 735, /* 0.97 */ 731, /* 0.98 */ 728, /* 0.99 */ 724, /* 1.00 */ 720, /* 1.01 */ }; void icossin2(int x, int y, int *cosp, int *sinp) { int sinsign, cossign, tan, tan10, rem; short *stp, *ctp; if(x == 0){ if(y >= 0) *sinp = ICOSSCALE, *cosp = 0; else *sinp = -ICOSSCALE, *cosp = 0; return; } sinsign = cossign = 1; if(x < 0){ cossign = -1; x = -x; } if(y < 0){ sinsign = -1; y = -y; } if(y > x){ tan = 1000*x/y; tan10 = tan/10; stp = &cosinus[tan10]; ctp = &sinus[tan10]; }else{ tan = 1000*y/x; tan10 = tan/10; stp = &sinus[tan10]; ctp = &cosinus[tan10]; } rem = tan-(tan10*10); *sinp = sinsign*(stp[0]+(stp[1]-stp[0])*rem/10); *cosp = cossign*(ctp[0]+(ctp[1]-ctp[0])*rem/10); } drawterm-20170818/libdraw/rectclip.c000066400000000000000000000010731314554504700172210ustar00rootroot00000000000000#include #include #include int rectclip(Rectangle *rp, Rectangle b) /* first by reference, second by value */ { Rectangle *bp = &b; /* * Expand rectXrect() in line for speed */ if((rp->min.xmax.x && bp->min.xmax.x && rp->min.ymax.y && bp->min.ymax.y)==0) return 0; /* They must overlap */ if(rp->min.x < bp->min.x) rp->min.x = bp->min.x; if(rp->min.y < bp->min.y) rp->min.y = bp->min.y; if(rp->max.x > bp->max.x) rp->max.x = bp->max.x; if(rp->max.y > bp->max.y) rp->max.y = bp->max.y; return 1; } drawterm-20170818/libdraw/rgb.c000066400000000000000000000032171314554504700161700ustar00rootroot00000000000000#include #include #include /* * This original version, although fast and a true inverse of * cmap2rgb, in the sense that rgb2cmap(cmap2rgb(c)) * returned the original color, does a terrible job for RGB * triples that do not appear in the color map, so it has been * replaced by the much slower version below, that loops * over the color map looking for the nearest point in RGB * space. There is no visual psychology reason for that * criterion, but it's easy to implement and the results are * far more pleasing. * int rgb2cmap(int cr, int cg, int cb) { int r, g, b, v, cv; if(cr < 0) cr = 0; else if(cr > 255) cr = 255; if(cg < 0) cg = 0; else if(cg > 255) cg = 255; if(cb < 0) cb = 0; else if(cb > 255) cb = 255; r = cr>>6; g = cg>>6; b = cb>>6; cv = cr; if(cg > cv) cv = cg; if(cb > cv) cv = cb; v = (cv>>4)&3; return ((((r<<2)+v)<<4)+(((g<<2)+b+v-r)&15)); } */ int rgb2cmap(int cr, int cg, int cb) { int i, r, g, b, sq; ulong rgb; int best, bestsq; best = 0; bestsq = 0x7FFFFFFF; for(i=0; i<256; i++){ rgb = cmap2rgb(i); r = (rgb>>16) & 0xFF; g = (rgb>>8) & 0xFF; b = (rgb>>0) & 0xFF; sq = (r-cr)*(r-cr)+(g-cg)*(g-cg)+(b-cb)*(b-cb); if(sq < bestsq){ bestsq = sq; best = i; } } return best; } int cmap2rgb(int c) { int j, num, den, r, g, b, v, rgb; r = c>>6; v = (c>>4)&3; j = (c-v+r)&15; g = j>>2; b = j&3; den=r; if(g>den) den=g; if(b>den) den=b; if(den==0) { v *= 17; rgb = (v<<16)|(v<<8)|v; } else{ num=17*(4*den+v); rgb = ((r*num/den)<<16)|((g*num/den)<<8)|(b*num/den); } return rgb; } int cmap2rgba(int c) { return (cmap2rgb(c)<<8)|0xFF; } drawterm-20170818/libip/000077500000000000000000000000001314554504700147225ustar00rootroot00000000000000drawterm-20170818/libip/Makefile000066400000000000000000000003411314554504700163600ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libip.a OFILES=\ eipfmt.$O\ parseip.$O\ classmask.$O\ bo.$O\ ipaux.$O\ default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/libip/bo.c000066400000000000000000000014531314554504700154710ustar00rootroot00000000000000#include #include #include void hnputv(void *p, uvlong v) { uchar *a; a = p; a[0] = v>>56; a[1] = v>>48; a[2] = v>>40; a[3] = v>>32; a[4] = v>>24; a[5] = v>>16; a[6] = v>>8; a[7] = v; } void hnputl(void *p, uint v) { uchar *a; a = p; a[0] = v>>24; a[1] = v>>16; a[2] = v>>8; a[3] = v; } void hnputs(void *p, ushort v) { uchar *a; a = p; a[0] = v>>8; a[1] = v; } uvlong nhgetv(void *p) { uchar *a; uvlong v; a = p; v = (uvlong)a[0]<<56; v |= (uvlong)a[1]<<48; v |= (uvlong)a[2]<<40; v |= (uvlong)a[3]<<32; v |= a[4]<<24; v |= a[5]<<16; v |= a[6]<<8; v |= a[7]<<0; return v; } uint nhgetl(void *p) { uchar *a; a = p; return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0); } ushort nhgets(void *p) { uchar *a; a = p; return (a[0]<<8)|(a[1]<<0); } drawterm-20170818/libip/classmask.c000066400000000000000000000035651314554504700170600ustar00rootroot00000000000000#include #include #include static uchar classmask[4][16] = { 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00, }; static uchar v6loopback[IPaddrlen] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 }; static uchar v6linklocal[IPaddrlen] = { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static uchar v6linklocalmask[IPaddrlen] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0 }; static int v6llpreflen = 8; /* link-local prefix length in bytes */ static uchar v6multicast[IPaddrlen] = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static uchar v6multicastmask[IPaddrlen] = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static int v6mcpreflen = 1; /* multicast prefix length */ static uchar v6solicitednode[IPaddrlen] = { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0xff, 0, 0, 0 }; static uchar v6solicitednodemask[IPaddrlen] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0 }; static int v6snpreflen = 13; uchar* defmask(uchar *ip) { if(isv4(ip)) return classmask[ip[IPv4off]>>6]; else { if(ipcmp(ip, v6loopback) == 0) return IPallbits; else if(memcmp(ip, v6linklocal, v6llpreflen) == 0) return v6linklocalmask; else if(memcmp(ip, v6solicitednode, v6snpreflen) == 0) return v6solicitednodemask; else if(memcmp(ip, v6multicast, v6mcpreflen) == 0) return v6multicastmask; return IPallbits; } } void maskip(uchar *from, uchar *mask, uchar *to) { int i; for(i = 0; i < IPaddrlen; i++) to[i] = from[i] & mask[i]; } drawterm-20170818/libip/eipfmt.c000066400000000000000000000042361314554504700163570ustar00rootroot00000000000000#include #include #include enum { Isprefix= 16, }; uchar prefixvals[256] = { [0x00] = 0 | Isprefix, [0x80] = 1 | Isprefix, [0xC0] = 2 | Isprefix, [0xE0] = 3 | Isprefix, [0xF0] = 4 | Isprefix, [0xF8] = 5 | Isprefix, [0xFC] = 6 | Isprefix, [0xFE] = 7 | Isprefix, [0xFF] = 8 | Isprefix, }; int eipfmt(Fmt *f) { char buf[5*8]; static char *efmt = "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux"; static char *ifmt = "%d.%d.%d.%d"; uchar *p, ip[16]; ulong *lp; ushort s; int i, j, n, eln, eli; switch(f->r) { case 'E': /* Ethernet address */ p = va_arg(f->args, uchar*); snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]); return fmtstrcpy(f, buf); case 'I': /* Ip address */ p = va_arg(f->args, uchar*); common: if(memcmp(p, v4prefix, 12) == 0){ snprint(buf, sizeof buf, ifmt, p[12], p[13], p[14], p[15]); return fmtstrcpy(f, buf); } /* find longest elision */ eln = eli = -1; for(i = 0; i < 16; i += 2){ for(j = i; j < 16; j += 2) if(p[j] != 0 || p[j+1] != 0) break; if(j > i && j - i > eln){ eli = i; eln = j - i; } } /* print with possible elision */ n = 0; for(i = 0; i < 16; i += 2){ if(i == eli){ n += sprint(buf+n, "::"); i += eln; if(i >= 16) break; } else if(i != 0) n += sprint(buf+n, ":"); s = (p[i]<<8) + p[i+1]; n += sprint(buf+n, "%ux", s); } return fmtstrcpy(f, buf); case 'i': /* v6 address as 4 longs */ lp = va_arg(f->args, ulong*); for(i = 0; i < 4; i++) hnputl(ip+4*i, *lp++); p = ip; goto common; case 'V': /* v4 ip address */ p = va_arg(f->args, uchar*); snprint(buf, sizeof buf, ifmt, p[0], p[1], p[2], p[3]); return fmtstrcpy(f, buf); case 'M': /* ip mask */ p = va_arg(f->args, uchar*); /* look for a prefix mask */ for(i = 0; i < 16; i++) if(p[i] != 0xff) break; if(i < 16){ if((prefixvals[p[i]] & Isprefix) == 0) goto common; for(j = i+1; j < 16; j++) if(p[j] != 0) goto common; n = 8*i + (prefixvals[p[i]] & ~Isprefix); } else n = 8*16; /* got one, use /xx format */ snprint(buf, sizeof buf, "/%d", n); return fmtstrcpy(f, buf); } return fmtstrcpy(f, "(eipfmt)"); } drawterm-20170818/libip/ipaux.c000066400000000000000000000027531314554504700162230ustar00rootroot00000000000000#include #include #include /* * well known IP addresses */ uchar IPv4bcast[IPaddrlen] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; uchar IPv4allsys[IPaddrlen] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xe0, 0, 0, 0x01 }; uchar IPv4allrouter[IPaddrlen] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xe0, 0, 0, 0x02 }; uchar IPallbits[IPaddrlen] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; uchar IPnoaddr[IPaddrlen]; /* * prefix of all v4 addresses */ uchar v4prefix[IPaddrlen] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0 }; int isv4(uchar *ip) { return memcmp(ip, v4prefix, IPv4off) == 0; } /* * the following routines are unrolled with no memset's to speed * up the usual case */ void v4tov6(uchar *v6, uchar *v4) { v6[0] = 0; v6[1] = 0; v6[2] = 0; v6[3] = 0; v6[4] = 0; v6[5] = 0; v6[6] = 0; v6[7] = 0; v6[8] = 0; v6[9] = 0; v6[10] = 0xff; v6[11] = 0xff; v6[12] = v4[0]; v6[13] = v4[1]; v6[14] = v4[2]; v6[15] = v4[3]; } int v6tov4(uchar *v4, uchar *v6) { if(v6[0] == 0 && v6[1] == 0 && v6[2] == 0 && v6[3] == 0 && v6[4] == 0 && v6[5] == 0 && v6[6] == 0 && v6[7] == 0 && v6[8] == 0 && v6[9] == 0 && v6[10] == 0xff && v6[11] == 0xff) { v4[0] = v6[12]; v4[1] = v6[13]; v4[2] = v6[14]; v4[3] = v6[15]; return 0; } else { memset(v4, 0, 4); if(memcmp(v6, IPnoaddr, IPaddrlen) == 0) return 0; return -1; } } drawterm-20170818/libip/parseip.c000066400000000000000000000067061314554504700165420ustar00rootroot00000000000000#include #include #include #include char* v4parseip(uchar *to, char *from) { int i; char *p; p = from; for(i = 0; i < 4 && *p; i++){ to[i] = strtoul(p, &p, 0); if(*p == '.') p++; } switch(CLASS(to)){ case 0: /* class A - 1 uchar net */ case 1: if(i == 3){ to[3] = to[2]; to[2] = to[1]; to[1] = 0; } else if (i == 2){ to[3] = to[1]; to[1] = 0; } break; case 2: /* class B - 2 uchar net */ if(i == 3){ to[3] = to[2]; to[2] = 0; } break; } return p; } static int ipcharok(int c) { return c == '.' || c == ':' || (isascii(c) && isxdigit(c)); } static int delimchar(int c) { if(c == '\0') return 1; if(c == '.' || c == ':' || (isascii(c) && isalnum(c))) return 0; return 1; } /* * `from' may contain an address followed by other characters, * at least in /boot, so we permit whitespace (and more) after the address. * we do ensure that "delete" cannot be parsed as "de::". * * some callers don't check the return value for errors, so * set `to' to something distinctive in the case of a parse error. */ vlong parseip(uchar *to, char *from) { int i, elipsis = 0, v4 = 1; ulong x; char *p, *op; memset(to, 0, IPaddrlen); p = from; for(i = 0; i < IPaddrlen && ipcharok(*p); i+=2){ op = p; x = strtoul(p, &p, 16); if(*p == '.' || (*p == 0 && i == 0)){ /* ends with v4? */ p = v4parseip(to+i, op); i += 4; break; } /* v6: at most 4 hex digits, followed by colon or delim */ if(x != (ushort)x || (*p != ':' && !delimchar(*p))) { memset(to, 0, IPaddrlen); return -1; /* parse error */ } to[i] = x>>8; to[i+1] = x; if(*p == ':'){ v4 = 0; if(*++p == ':'){ /* :: is elided zero short(s) */ if (elipsis) { memset(to, 0, IPaddrlen); return -1; /* second :: */ } elipsis = i+2; p++; } } else if (p == op) /* strtoul made no progress? */ break; } if (p == from || !delimchar(*p)) { memset(to, 0, IPaddrlen); return -1; /* parse error */ } if(i < IPaddrlen){ memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis); memset(&to[elipsis], 0, IPaddrlen-i); } if(v4){ to[10] = to[11] = 0xff; return nhgetl(to + IPv4off); } else return 6; } /* * hack to allow ip v4 masks to be entered in the old * style */ vlong parseipmask(uchar *to, char *from) { int i, w; vlong x; uchar *p; if(*from == '/'){ /* as a number of prefix bits */ i = atoi(from+1); if(i < 0) i = 0; if(i > 128) i = 128; w = i; memset(to, 0, IPaddrlen); for(p = to; i >= 8; i -= 8) *p++ = 0xff; if(i > 0) *p = ~((1<<(8-i))-1); x = nhgetl(to+IPv4off); /* * identify as ipv6 if the mask is inexpressible as a v4 mask * (because it has too few mask bits). Arguably, we could * always return 6 here. */ if (w < 8*(IPaddrlen-IPv4addrlen)) return 6; } else { /* as a straight v4 bit mask */ x = parseip(to, from); if (x != -1) x = (ulong)nhgetl(to + IPv4off); if(memcmp(to, v4prefix, IPv4off) == 0) memset(to, 0xff, IPv4off); } return x; } /* * parse a v4 ip address/mask in cidr format */ char* v4parsecidr(uchar *addr, uchar *mask, char *from) { int i; char *p; uchar *a; p = v4parseip(addr, from); if(*p == '/'){ /* as a number of prefix bits */ i = strtoul(p+1, &p, 0); if(i > 32) i = 32; memset(mask, 0, IPv4addrlen); for(a = mask; i >= 8; i -= 8) *a++ = 0xff; if(i > 0) *a = ~((1<<(8-i))-1); } else memcpy(mask, defmask(addr), IPv4addrlen); return p; } drawterm-20170818/libmemdraw/000077500000000000000000000000001314554504700157465ustar00rootroot00000000000000drawterm-20170818/libmemdraw/Makefile000066400000000000000000000006071314554504700174110ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libmemdraw.a OFILES=\ alloc.$O\ arc.$O\ cload.$O\ cmap.$O\ cread.$O\ defont.$O\ draw.$O\ ellipse.$O\ fillpoly.$O\ hwdraw.$O\ line.$O\ load.$O\ openmemsubfont.$O\ poly.$O\ read.$O\ string.$O\ subfont.$O\ unload.$O\ write.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/libmemdraw/alloc.c000066400000000000000000000065221314554504700172110ustar00rootroot00000000000000#include #include #include #include #define poolalloc(a, b) malloc(b) #define poolfree(a, b) free(b) void memimagemove(void *from, void *to) { Memdata *md; md = *(Memdata**)to; if(md->base != from){ print("compacted data not right: #%p\n", md->base); abort(); } md->base = to; /* if allocmemimage changes this must change too */ md->bdata = (uchar*)md->base+sizeof(Memdata*)+sizeof(ulong); } Memimage* allocmemimaged(Rectangle r, ulong chan, Memdata *md, void *X) { int d; ulong l; Memimage *i; if(Dx(r) <= 0 || Dy(r) <= 0){ werrstr("bad rectangle %R", r); return nil; } if((d = chantodepth(chan)) == 0) { werrstr("bad channel descriptor %.8lux", chan); return nil; } l = wordsperline(r, d); i = mallocz(sizeof(Memimage), 1); if(i == nil) return nil; i->X = X; i->data = md; i->zero = sizeof(ulong)*l*r.min.y; if(r.min.x >= 0) i->zero += (r.min.x*d)/8; else i->zero -= (-r.min.x*d+7)/8; i->zero = -i->zero; i->width = l; i->r = r; i->clipr = r; i->flags = 0; i->layer = nil; i->cmap = memdefcmap; if(memsetchan(i, chan) < 0){ free(i); return nil; } return i; } Memimage* _allocmemimage(Rectangle r, ulong chan) { int d; u32int l, nw; uchar *p; Memdata *md; Memimage *i; if((d = chantodepth(chan)) == 0) { werrstr("bad channel descriptor %.8lux", chan); return nil; } l = wordsperline(r, d); nw = l*Dy(r); md = malloc(sizeof(Memdata)); if(md == nil) return nil; md->ref = 1; md->base = poolalloc(imagmem, sizeof(Memdata*)+(1+nw)*sizeof(ulong)); if(md->base == nil){ free(md); return nil; } p = (uchar*)md->base; *(Memdata**)p = md; p += sizeof(Memdata*); *(ulong*)p = getcallerpc(&r); p += sizeof(ulong); /* if this changes, memimagemove must change too */ md->bdata = p; md->allocd = 1; i = allocmemimaged(r, chan, md, nil); if(i == nil){ poolfree(imagmem, md->base); free(md); return nil; } md->imref = i; return i; } void _freememimage(Memimage *i) { if(i == nil) return; if(i->data->ref-- == 1 && i->data->allocd){ if(i->data->base) poolfree(imagmem, i->data->base); free(i->data); } free(i); } /* * Wordaddr is deprecated. */ ulong* wordaddr(Memimage *i, Point p) { return (ulong*) ((uintptr)byteaddr(i, p) & ~(sizeof(ulong)-1)); } uchar* byteaddr(Memimage *i, Point p) { uchar *a; a = i->data->bdata+i->zero+sizeof(ulong)*p.y*i->width; if(i->depth < 8){ /* * We need to always round down, * but C rounds toward zero. */ int np; np = 8/i->depth; if(p.x < 0) return a+(p.x-np+1)/np; else return a+p.x/np; } else return a+p.x*(i->depth/8); } int memsetchan(Memimage *i, ulong chan) { int d; int t, j, k; ulong cc; int bytes; if((d = chantodepth(chan)) == 0) { werrstr("bad channel descriptor"); return -1; } i->depth = d; i->chan = chan; i->flags &= ~(Fgrey|Falpha|Fcmap|Fbytes); bytes = 1; for(cc=chan, j=0, k=0; cc; j+=NBITS(cc), cc>>=8, k++){ t=TYPE(cc); if(t < 0 || t >= NChan){ werrstr("bad channel string"); return -1; } if(t == CGrey) i->flags |= Fgrey; if(t == CAlpha) i->flags |= Falpha; if(t == CMap && i->cmap == nil){ i->cmap = memdefcmap; i->flags |= Fcmap; } i->shift[t] = j; i->mask[t] = (1<nbits[t] = NBITS(cc); if(NBITS(cc) != 8) bytes = 0; } i->nchan = k; if(bytes) i->flags |= Fbytes; return 0; } drawterm-20170818/libmemdraw/alpha.hoc000066400000000000000000000003341314554504700175260ustar00rootroot00000000000000func f(x) { return x-x%1 } func pixel(dr, dg, db, da, sr, sg, sb, sa, m) { M = 255-f((sa*m)/255) print f((sr*m+dr*M)/255), " ", f((sg*m+dg*M)/255), " ", f((sb*m+db*M)/255), " ", f((sa*m+da*M)/255), "\n" return 0 } drawterm-20170818/libmemdraw/arc.c000066400000000000000000000050601314554504700166600ustar00rootroot00000000000000#include #include #include #include #include /* * elarc(dst,c,a,b,t,src,sp,alpha,phi) * draws the part of an ellipse between rays at angles alpha and alpha+phi * measured counterclockwise from the positive x axis. other * arguments are as for ellipse(dst,c,a,b,t,src,sp) */ enum { R, T, L, B /* right, top, left, bottom */ }; static Point corners[] = { {1,1}, {-1,1}, {-1,-1}, {1,-1} }; static Point p00; /* * make a "wedge" mask covering the desired angle and contained in * a surrounding square; draw a full ellipse; intersect that with the * wedge to make a mask through which to copy src to dst. */ void memarc(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int alpha, int phi, int op) { int i, w, beta, tmp, c1, c2, m, m1; Rectangle rect; Point p, bnd[8]; Memimage *wedge, *figure, *mask; if(a < 0) a = -a; if(b < 0) b = -b; w = t; if(w < 0) w = 0; alpha = -alpha; /* compensate for upside-down coords */ phi = -phi; beta = alpha + phi; if(phi < 0){ tmp = alpha; alpha = beta; beta = tmp; phi = -phi; } if(phi >= 360){ memellipse(dst, c, a, b, t, src, sp, op); return; } while(alpha < 0) alpha += 360; while(beta < 0) beta += 360; c1 = alpha/90 & 3; /* number of nearest corner */ c2 = beta/90 & 3; /* * icossin returns point at radius ICOSSCALE. * multiplying by m1 moves it outside the ellipse */ rect = Rect(-a-w, -b-w, a+w+1, b+w+1); m = rect.max.x; /* inradius of bounding square */ if(m < rect.max.y) m = rect.max.y; m1 = (m+ICOSSCALE-1) >> 10; m = m1 << 10; /* assure m1*cossin is inside */ i = 0; bnd[i++] = Pt(0,0); icossin(alpha, &p.x, &p.y); bnd[i++] = mulpt(p, m1); for(;;) { bnd[i++] = mulpt(corners[c1], m); if(c1==c2 && phi<180) break; c1 = (c1+1) & 3; phi -= 90; } icossin(beta, &p.x, &p.y); bnd[i++] = mulpt(p, m1); figure = nil; mask = nil; wedge = allocmemimage(rect, GREY1); if(wedge == nil) goto Return; memfillcolor(wedge, DTransparent); memfillpoly(wedge, bnd, i, ~0, memopaque, p00, S); figure = allocmemimage(rect, GREY1); if(figure == nil) goto Return; memfillcolor(figure, DTransparent); memellipse(figure, p00, a, b, t, memopaque, p00, S); mask = allocmemimage(rect, GREY1); if(mask == nil) goto Return; memfillcolor(mask, DTransparent); memimagedraw(mask, rect, figure, rect.min, wedge, rect.min, S); c = subpt(c, dst->r.min); memdraw(dst, dst->r, src, subpt(sp, c), mask, subpt(p00, c), op); Return: freememimage(wedge); freememimage(figure); freememimage(mask); } drawterm-20170818/libmemdraw/arctest.c000066400000000000000000000015411314554504700175600ustar00rootroot00000000000000#include #include #include #include #include extern int drawdebug; void main(int argc, char **argv) { char cc; Memimage *x; Point c = {208,871}; int a = 441; int b = 441; int thick = 0; Point sp = {0,0}; int alpha = 51; int phi = 3; vlong t0, t1; int i, n; vlong del; memimageinit(); x = allocmemimage(Rect(0,0,1000,1000), CMAP8); n = atoi(argv[1]); t0 = nsec(); t0 = nsec(); t0 = nsec(); t1 = nsec(); del = t1-t0; t0 = nsec(); for(i=0; i #include #include #include int _cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) { int y, bpl, c, cnt, offs; uchar mem[NMEM], *memp, *omemp, *emem, *linep, *elinep, *u, *eu; if(!rectinrect(r, i->r)) return -1; bpl = bytesperline(r, i->depth); u = data; eu = data+ndata; memp = mem; emem = mem+NMEM; y = r.min.y; linep = byteaddr(i, Pt(r.min.x, y)); elinep = linep+bpl; for(;;){ if(linep == elinep){ if(++y == r.max.y) break; linep = byteaddr(i, Pt(r.min.x, y)); elinep = linep+bpl; } if(u == eu){ /* buffer too small */ return -1; } c = *u++; if(c >= 128){ for(cnt=c-128+1; cnt!=0 ;--cnt){ if(u == eu){ /* buffer too small */ return -1; } if(linep == elinep){ /* phase error */ return -1; } *linep++ = *u; *memp++ = *u++; if(memp == emem) memp = mem; } } else{ if(u == eu) /* short buffer */ return -1; offs = *u++ + ((c&3)<<8)+1; if(memp-mem < offs) omemp = memp+(NMEM-offs); else omemp = memp-offs; for(cnt=(c>>2)+NMATCH; cnt!=0; --cnt){ if(linep == elinep) /* phase error */ return -1; *linep++ = *omemp; *memp++ = *omemp++; if(omemp == emem) omemp = mem; if(memp == emem) memp = mem; } } } return u-data; } drawterm-20170818/libmemdraw/cmap.c000066400000000000000000000610761314554504700170440ustar00rootroot00000000000000/* * generated by mkcmap.c */ #include #include #include #include static Memcmap def = { /* cmap2rgb */ { 0x00,0x00,0x00,0x00,0x00,0x44,0x00,0x00,0x88,0x00,0x00,0xcc,0x00,0x44,0x00,0x00, 0x44,0x44,0x00,0x44,0x88,0x00,0x44,0xcc,0x00,0x88,0x00,0x00,0x88,0x44,0x00,0x88, 0x88,0x00,0x88,0xcc,0x00,0xcc,0x00,0x00,0xcc,0x44,0x00,0xcc,0x88,0x00,0xcc,0xcc, 0x00,0xdd,0xdd,0x11,0x11,0x11,0x00,0x00,0x55,0x00,0x00,0x99,0x00,0x00,0xdd,0x00, 0x55,0x00,0x00,0x55,0x55,0x00,0x4c,0x99,0x00,0x49,0xdd,0x00,0x99,0x00,0x00,0x99, 0x4c,0x00,0x99,0x99,0x00,0x93,0xdd,0x00,0xdd,0x00,0x00,0xdd,0x49,0x00,0xdd,0x93, 0x00,0xee,0x9e,0x00,0xee,0xee,0x22,0x22,0x22,0x00,0x00,0x66,0x00,0x00,0xaa,0x00, 0x00,0xee,0x00,0x66,0x00,0x00,0x66,0x66,0x00,0x55,0xaa,0x00,0x4f,0xee,0x00,0xaa, 0x00,0x00,0xaa,0x55,0x00,0xaa,0xaa,0x00,0x9e,0xee,0x00,0xee,0x00,0x00,0xee,0x4f, 0x00,0xff,0x55,0x00,0xff,0xaa,0x00,0xff,0xff,0x33,0x33,0x33,0x00,0x00,0x77,0x00, 0x00,0xbb,0x00,0x00,0xff,0x00,0x77,0x00,0x00,0x77,0x77,0x00,0x5d,0xbb,0x00,0x55, 0xff,0x00,0xbb,0x00,0x00,0xbb,0x5d,0x00,0xbb,0xbb,0x00,0xaa,0xff,0x00,0xff,0x00, 0x44,0x00,0x44,0x44,0x00,0x88,0x44,0x00,0xcc,0x44,0x44,0x00,0x44,0x44,0x44,0x44, 0x44,0x88,0x44,0x44,0xcc,0x44,0x88,0x00,0x44,0x88,0x44,0x44,0x88,0x88,0x44,0x88, 0xcc,0x44,0xcc,0x00,0x44,0xcc,0x44,0x44,0xcc,0x88,0x44,0xcc,0xcc,0x44,0x00,0x00, 0x55,0x00,0x00,0x55,0x00,0x55,0x4c,0x00,0x99,0x49,0x00,0xdd,0x55,0x55,0x00,0x55, 0x55,0x55,0x4c,0x4c,0x99,0x49,0x49,0xdd,0x4c,0x99,0x00,0x4c,0x99,0x4c,0x4c,0x99, 0x99,0x49,0x93,0xdd,0x49,0xdd,0x00,0x49,0xdd,0x49,0x49,0xdd,0x93,0x49,0xdd,0xdd, 0x4f,0xee,0xee,0x66,0x00,0x00,0x66,0x00,0x66,0x55,0x00,0xaa,0x4f,0x00,0xee,0x66, 0x66,0x00,0x66,0x66,0x66,0x55,0x55,0xaa,0x4f,0x4f,0xee,0x55,0xaa,0x00,0x55,0xaa, 0x55,0x55,0xaa,0xaa,0x4f,0x9e,0xee,0x4f,0xee,0x00,0x4f,0xee,0x4f,0x4f,0xee,0x9e, 0x55,0xff,0xaa,0x55,0xff,0xff,0x77,0x00,0x00,0x77,0x00,0x77,0x5d,0x00,0xbb,0x55, 0x00,0xff,0x77,0x77,0x00,0x77,0x77,0x77,0x5d,0x5d,0xbb,0x55,0x55,0xff,0x5d,0xbb, 0x00,0x5d,0xbb,0x5d,0x5d,0xbb,0xbb,0x55,0xaa,0xff,0x55,0xff,0x00,0x55,0xff,0x55, 0x88,0x00,0x88,0x88,0x00,0xcc,0x88,0x44,0x00,0x88,0x44,0x44,0x88,0x44,0x88,0x88, 0x44,0xcc,0x88,0x88,0x00,0x88,0x88,0x44,0x88,0x88,0x88,0x88,0x88,0xcc,0x88,0xcc, 0x00,0x88,0xcc,0x44,0x88,0xcc,0x88,0x88,0xcc,0xcc,0x88,0x00,0x00,0x88,0x00,0x44, 0x99,0x00,0x4c,0x99,0x00,0x99,0x93,0x00,0xdd,0x99,0x4c,0x00,0x99,0x4c,0x4c,0x99, 0x4c,0x99,0x93,0x49,0xdd,0x99,0x99,0x00,0x99,0x99,0x4c,0x99,0x99,0x99,0x93,0x93, 0xdd,0x93,0xdd,0x00,0x93,0xdd,0x49,0x93,0xdd,0x93,0x93,0xdd,0xdd,0x99,0x00,0x00, 0xaa,0x00,0x00,0xaa,0x00,0x55,0xaa,0x00,0xaa,0x9e,0x00,0xee,0xaa,0x55,0x00,0xaa, 0x55,0x55,0xaa,0x55,0xaa,0x9e,0x4f,0xee,0xaa,0xaa,0x00,0xaa,0xaa,0x55,0xaa,0xaa, 0xaa,0x9e,0x9e,0xee,0x9e,0xee,0x00,0x9e,0xee,0x4f,0x9e,0xee,0x9e,0x9e,0xee,0xee, 0xaa,0xff,0xff,0xbb,0x00,0x00,0xbb,0x00,0x5d,0xbb,0x00,0xbb,0xaa,0x00,0xff,0xbb, 0x5d,0x00,0xbb,0x5d,0x5d,0xbb,0x5d,0xbb,0xaa,0x55,0xff,0xbb,0xbb,0x00,0xbb,0xbb, 0x5d,0xbb,0xbb,0xbb,0xaa,0xaa,0xff,0xaa,0xff,0x00,0xaa,0xff,0x55,0xaa,0xff,0xaa, 0xcc,0x00,0xcc,0xcc,0x44,0x00,0xcc,0x44,0x44,0xcc,0x44,0x88,0xcc,0x44,0xcc,0xcc, 0x88,0x00,0xcc,0x88,0x44,0xcc,0x88,0x88,0xcc,0x88,0xcc,0xcc,0xcc,0x00,0xcc,0xcc, 0x44,0xcc,0xcc,0x88,0xcc,0xcc,0xcc,0xcc,0x00,0x00,0xcc,0x00,0x44,0xcc,0x00,0x88, 0xdd,0x00,0x93,0xdd,0x00,0xdd,0xdd,0x49,0x00,0xdd,0x49,0x49,0xdd,0x49,0x93,0xdd, 0x49,0xdd,0xdd,0x93,0x00,0xdd,0x93,0x49,0xdd,0x93,0x93,0xdd,0x93,0xdd,0xdd,0xdd, 0x00,0xdd,0xdd,0x49,0xdd,0xdd,0x93,0xdd,0xdd,0xdd,0xdd,0x00,0x00,0xdd,0x00,0x49, 0xee,0x00,0x4f,0xee,0x00,0x9e,0xee,0x00,0xee,0xee,0x4f,0x00,0xee,0x4f,0x4f,0xee, 0x4f,0x9e,0xee,0x4f,0xee,0xee,0x9e,0x00,0xee,0x9e,0x4f,0xee,0x9e,0x9e,0xee,0x9e, 0xee,0xee,0xee,0x00,0xee,0xee,0x4f,0xee,0xee,0x9e,0xee,0xee,0xee,0xee,0x00,0x00, 0xff,0x00,0x00,0xff,0x00,0x55,0xff,0x00,0xaa,0xff,0x00,0xff,0xff,0x55,0x00,0xff, 0x55,0x55,0xff,0x55,0xaa,0xff,0x55,0xff,0xff,0xaa,0x00,0xff,0xaa,0x55,0xff,0xaa, 0xaa,0xff,0xaa,0xff,0xff,0xff,0x00,0xff,0xff,0x55,0xff,0xff,0xaa,0xff,0xff,0xff, }, /* rgb2cmap */ { 0x00,0x00,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36, 0x00,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36, 0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36, 0x04,0x04,0x04,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29, 0x04,0x04,0x04,0x05,0x05,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a, 0x15,0x15,0x15,0x05,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a, 0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a, 0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a, 0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d, 0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e, 0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e, 0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e, 0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e, 0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21, 0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21, 0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32, 0x00,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36, 0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36, 0x11,0x11,0x22,0x22,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36, 0x04,0x04,0x22,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29, 0x04,0x04,0x04,0x05,0x05,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a, 0x15,0x15,0x15,0x05,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a, 0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a, 0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a, 0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d, 0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e, 0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e, 0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e, 0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e, 0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21, 0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21, 0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32, 0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36, 0x11,0x11,0x22,0x22,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36, 0x11,0x22,0x22,0x22,0x33,0x33,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36, 0x04,0x22,0x22,0x33,0x33,0x33,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29, 0x04,0x04,0x33,0x33,0x33,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a, 0x15,0x15,0x33,0x33,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a, 0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a, 0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a, 0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d, 0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e, 0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e, 0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e, 0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e, 0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21, 0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21, 0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32, 0x4f,0x4f,0x22,0x40,0x40,0x40,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64, 0x4f,0x22,0x22,0x22,0x40,0x40,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64, 0x22,0x22,0x22,0x33,0x33,0x33,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64, 0x43,0x22,0x33,0x33,0x33,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x46,0x57,0x68, 0x43,0x43,0x33,0x33,0x44,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x57,0x57,0x68, 0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68, 0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79, 0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x5b,0x79, 0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x5a,0x4a,0x4a,0x4a,0x5b,0x6c, 0x47,0x47,0x47,0x48,0x48,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x5b,0x6c, 0x58,0x58,0x58,0x59,0x59,0x59,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d, 0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x4c,0x4d,0x4d,0x4d,0x6b,0x4e,0x4e,0x4e,0x6c,0x7d, 0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x4c,0x4d,0x4d,0x4d,0x5e,0x4e,0x4e,0x4e,0x5f,0x5f, 0x5c,0x5c,0x5c,0x4c,0x5d,0x5d,0x5d,0x4d,0x4d,0x5e,0x5e,0x4e,0x4e,0x5f,0x5f,0x60, 0x5c,0x5c,0x5c,0x5d,0x5d,0x6e,0x6e,0x5e,0x5e,0x5e,0x6f,0x6f,0x5f,0x5f,0x60,0x60, 0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x5f,0x60,0x60,0x71, 0x4f,0x4f,0x40,0x40,0x40,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75, 0x4f,0x4f,0x22,0x40,0x40,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75, 0x43,0x22,0x33,0x33,0x33,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75, 0x43,0x43,0x33,0x33,0x44,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x57,0x57,0x68, 0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68, 0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79, 0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79, 0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x5b,0x79, 0x47,0x47,0x47,0x48,0x48,0x48,0x59,0x49,0x49,0x49,0x5a,0x4a,0x4a,0x5b,0x5b,0x6c, 0x58,0x58,0x58,0x48,0x59,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c, 0x69,0x69,0x69,0x59,0x59,0x6a,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d, 0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x7b,0x4d,0x4d,0x4d,0x6b,0x4e,0x4e,0x4e,0x7d,0x7d, 0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x7b,0x4d,0x4d,0x4d,0x5e,0x4e,0x4e,0x4e,0x5f,0x7d, 0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x5d,0x4d,0x5e,0x5e,0x5e,0x4e,0x4e,0x5f,0x5f,0x60, 0x6d,0x6d,0x6d,0x5d,0x6e,0x6e,0x6e,0x5e,0x5e,0x6f,0x6f,0x70,0x5f,0x5f,0x60,0x60, 0x7e,0x7e,0x7e,0x6e,0x6e,0x7f,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x70,0x60,0x60,0x71, 0x50,0x50,0x50,0x40,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75, 0x50,0x50,0x50,0x40,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75, 0x50,0x50,0x33,0x33,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75, 0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68, 0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79, 0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79, 0x54,0x54,0x54,0x55,0x55,0x55,0x66,0x66,0x56,0x67,0x67,0x78,0x78,0x68,0x68,0x79, 0x47,0x47,0x47,0x48,0x48,0x48,0x66,0x49,0x49,0x49,0x78,0x78,0x4a,0x4a,0x5b,0x79, 0x47,0x47,0x47,0x48,0x48,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c, 0x58,0x58,0x58,0x59,0x59,0x59,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d, 0x69,0x69,0x69,0x59,0x6a,0x6a,0x6a,0x7b,0x5a,0x6b,0x6b,0x6b,0x7c,0x6c,0x6c,0x7d, 0x7a,0x7a,0x7a,0x4c,0x4c,0x7b,0x7b,0x7b,0x4d,0x6b,0x6b,0x7c,0x7c,0x4e,0x7d,0x7d, 0x4b,0x4b,0x4b,0x4c,0x4c,0x7b,0x7b,0x4d,0x4d,0x5e,0x7c,0x7c,0x4e,0x5f,0x5f,0x7d, 0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x6e,0x4d,0x5e,0x5e,0x6f,0x4e,0x5f,0x5f,0x60,0x60, 0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x6e,0x5e,0x6f,0x6f,0x6f,0x70,0x5f,0x60,0x60,0x71, 0x7e,0x7e,0x7e,0x6e,0x7f,0x7f,0x7f,0x7f,0x6f,0x70,0x70,0x70,0x70,0x60,0x71,0x71, 0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75, 0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75, 0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75, 0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79, 0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79, 0x54,0x54,0x54,0x55,0x55,0x55,0x66,0x66,0x56,0x67,0x67,0x78,0x78,0x68,0x68,0x79, 0x65,0x65,0x65,0x55,0x55,0x66,0x66,0x66,0x77,0x67,0x78,0x78,0x78,0x78,0x79,0x79, 0x65,0x65,0x65,0x48,0x48,0x66,0x66,0x77,0x77,0x77,0x78,0x78,0x78,0x5b,0x79,0x79, 0x76,0x76,0x76,0x48,0x59,0x59,0x77,0x77,0x77,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c, 0x69,0x69,0x69,0x59,0x59,0x6a,0x6a,0x77,0x5a,0x5a,0x6b,0x6b,0x5b,0x6c,0x6c,0x7d, 0x69,0x69,0x69,0x6a,0x6a,0x6a,0x7b,0x7b,0x5a,0x6b,0x6b,0x7c,0x7c,0x6c,0x7d,0x7d, 0x7a,0x7a,0x7a,0x4c,0x7b,0x7b,0x7b,0x7b,0x4d,0x6b,0x7c,0x7c,0x7c,0x7c,0x7d,0x7d, 0x7a,0x7a,0x7a,0x4c,0x7b,0x7b,0x7b,0x7b,0x4d,0x5e,0x7c,0x7c,0x7c,0x5f,0x5f,0x7d, 0x6d,0x6d,0x6d,0x5d,0x5d,0x6e,0x7b,0x5e,0x5e,0x6f,0x6f,0x7c,0x5f,0x5f,0x60,0x60, 0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x5f,0x60,0x60,0x71, 0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x6f,0x70,0x70,0x70,0x70,0x60,0x71,0x71, 0x72,0x72,0x72,0x8f,0x8f,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75, 0x72,0x72,0x72,0x8f,0x8f,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75, 0x72,0x72,0x72,0x83,0x83,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75, 0x82,0x82,0x82,0x83,0x83,0x83,0x83,0x84,0x84,0x84,0x84,0x85,0x85,0x85,0x96,0x79, 0x82,0x82,0x82,0x83,0x83,0x83,0x66,0x84,0x84,0x84,0x67,0x85,0x85,0x85,0x96,0x79, 0x65,0x65,0x65,0x83,0x83,0x66,0x66,0x66,0x84,0x84,0x78,0x78,0x85,0x85,0x96,0x79, 0x65,0x65,0x65,0x83,0x66,0x66,0x66,0x77,0x77,0x77,0x78,0x78,0x78,0x96,0x79,0x79, 0x76,0x76,0x76,0x87,0x87,0x66,0x77,0x77,0x77,0x88,0x78,0x89,0x89,0x89,0x89,0x79, 0x76,0x76,0x76,0x87,0x87,0x87,0x77,0x77,0x88,0x88,0x88,0x89,0x89,0x89,0x9a,0x9a, 0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x6b,0x89,0x89,0x9a,0x9a,0x7d, 0x7a,0x7a,0x7a,0x87,0x6a,0x7b,0x7b,0x7b,0x88,0x6b,0x6b,0x7c,0x7c,0x9a,0x7d,0x7d, 0x8a,0x8a,0x8a,0x8b,0x8b,0x7b,0x7b,0x8c,0x8c,0x8c,0x7c,0x7c,0x8d,0x8d,0x7d,0x7d, 0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x7b,0x8c,0x8c,0x8c,0x7c,0x8d,0x8d,0x8d,0x9e,0x9e, 0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x9c,0x8c,0x8c,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0x9e, 0x9b,0x9b,0x9b,0x9c,0x9c,0x9c,0x7f,0x8c,0x9d,0x9d,0x70,0x70,0x9e,0x9e,0x9e,0x71, 0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x9d,0x70,0x70,0x70,0x9e,0x9e,0x71,0x71, 0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3, 0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3, 0x82,0x82,0x82,0x83,0x83,0x83,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3, 0x82,0x82,0x82,0x83,0x83,0x83,0x83,0x84,0x84,0x84,0x95,0x85,0x85,0x85,0x96,0xa7, 0x82,0x82,0x82,0x83,0x83,0x83,0x94,0x84,0x84,0x84,0x95,0x85,0x85,0x96,0x96,0xa7, 0x82,0x82,0x82,0x83,0x83,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7, 0x76,0x76,0x76,0x83,0x94,0x94,0x77,0x77,0x77,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7, 0x76,0x76,0x76,0x87,0x87,0x87,0x77,0x77,0x88,0x88,0x88,0x89,0x89,0x89,0x9a,0x9a, 0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x99,0x89,0x89,0x9a,0x9a,0xab, 0x86,0x86,0x86,0x87,0x87,0x98,0x98,0x88,0x88,0x99,0x99,0x89,0x89,0x9a,0x9a,0xab, 0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab, 0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x8c,0x8d,0x8d,0x8d,0xab,0xbc, 0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x9d,0x8d,0x8d,0x8d,0x9e,0x9e, 0x9b,0x9b,0x9b,0x8b,0x9c,0x9c,0x9c,0x8c,0x9d,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0xaf, 0x9b,0x9b,0x9b,0x9c,0x9c,0xad,0xad,0x9d,0x9d,0x9d,0xae,0xae,0x9e,0x9e,0xaf,0xaf, 0xac,0xac,0xac,0xad,0xad,0xad,0xad,0x9d,0xae,0xae,0xae,0xbf,0x9e,0xaf,0xaf,0xaf, 0x9f,0x9f,0x9f,0x8f,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4, 0x9f,0x9f,0x9f,0x8f,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4, 0x9f,0x9f,0x9f,0x83,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4, 0x82,0x82,0x82,0x83,0x83,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0x96,0xa7, 0x93,0x93,0x93,0x83,0x94,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7, 0x93,0x93,0x93,0x94,0x94,0x94,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8, 0xa4,0xa4,0xa4,0x94,0x94,0xa5,0xa5,0x77,0x95,0x95,0xa6,0xa6,0x96,0xa7,0xa7,0xb8, 0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x99,0x89,0x89,0x9a,0x9a,0xb8, 0x86,0x86,0x86,0x87,0x87,0x98,0x98,0x88,0x88,0x99,0x99,0x89,0x89,0x9a,0x9a,0xab, 0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab, 0x97,0x97,0x97,0x98,0x98,0xa9,0xa9,0x99,0x99,0x99,0xaa,0xaa,0x9a,0xab,0xab,0xbc, 0x8a,0x8a,0x8a,0x8b,0x8b,0xa9,0xa9,0x8c,0x8c,0x8c,0xaa,0x8d,0x8d,0x8d,0xab,0xbc, 0x8a,0x8a,0x8a,0x8b,0x8b,0x9c,0x9c,0x8c,0x8c,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0xbc, 0x9b,0x9b,0x9b,0x9c,0x9c,0x9c,0xad,0x9d,0x9d,0x9d,0xae,0x8d,0x9e,0x9e,0xaf,0xaf, 0xac,0xac,0xac,0x9c,0xad,0xad,0xad,0x9d,0x9d,0xae,0xae,0xae,0x9e,0xaf,0xaf,0xaf, 0xbd,0xbd,0xbd,0xad,0xad,0xbe,0xbe,0xbe,0xae,0xae,0xbf,0xbf,0xbf,0xaf,0xaf,0xb0, 0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4, 0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4, 0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4, 0x93,0x93,0x93,0x94,0x94,0x94,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8, 0xa4,0xa4,0xa4,0x94,0x94,0xa5,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8, 0xa4,0xa4,0xa4,0x94,0xa5,0xa5,0xa5,0xb6,0x95,0xa6,0xa6,0xa6,0xb7,0xa7,0xa7,0xb8, 0xa4,0xa4,0xa4,0xa5,0xa5,0xa5,0xb6,0xb6,0x95,0xa6,0xa6,0xb7,0xb7,0xa7,0xb8,0xb8, 0xb5,0xb5,0xb5,0x87,0x87,0xb6,0xb6,0xb6,0x88,0x99,0xa6,0xb7,0xb7,0x9a,0xb8,0xb8, 0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab, 0x97,0x97,0x97,0x98,0x98,0xa9,0xa9,0x99,0x99,0x99,0xaa,0xaa,0x9a,0xab,0xab,0xbc, 0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xa9,0xa9,0x99,0xaa,0xaa,0xaa,0xbb,0xab,0xab,0xbc, 0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xba,0xba,0x8c,0xaa,0xaa,0xbb,0xbb,0xab,0xbc,0xbc, 0xb9,0xb9,0xb9,0x9c,0x9c,0xba,0xba,0xba,0x9d,0x9d,0xbb,0xbb,0xbb,0x9e,0x9e,0xbc, 0xac,0xac,0xac,0x9c,0x9c,0xad,0xad,0x9d,0x9d,0xae,0xae,0xae,0x9e,0x9e,0xaf,0xaf, 0xac,0xac,0xac,0xad,0xad,0xad,0xbe,0xbe,0xae,0xae,0xae,0xbf,0x9e,0xaf,0xaf,0xb0, 0xbd,0xbd,0xbd,0xbe,0xbe,0xbe,0xbe,0xbe,0xae,0xbf,0xbf,0xbf,0xbf,0xaf,0xb0,0xb0, 0xb1,0xb1,0xb1,0xce,0xce,0xb2,0xb2,0xcf,0xcf,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4, 0xb1,0xb1,0xb1,0xce,0xce,0xb2,0xb2,0xcf,0xcf,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4, 0xb1,0xb1,0xb1,0xc2,0xc2,0xb2,0xb2,0xc3,0xc3,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4, 0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xa5,0xc3,0xc3,0xc3,0xa6,0xc4,0xc4,0xc4,0xa7,0xb8, 0xc1,0xc1,0xc1,0xc2,0xc2,0xa5,0xb6,0xc3,0xc3,0xc3,0xa6,0xc4,0xc4,0xc4,0xb8,0xb8, 0xb5,0xb5,0xb5,0xc2,0xa5,0xb6,0xb6,0xb6,0xc3,0xa6,0xa6,0xb7,0xb7,0xc4,0xb8,0xb8, 0xb5,0xb5,0xb5,0xa5,0xb6,0xb6,0xb6,0xb6,0xc3,0xa6,0xb7,0xb7,0xb7,0xb7,0xb8,0xb8, 0xc5,0xc5,0xc5,0xc6,0xc6,0xb6,0xb6,0xc7,0xc7,0xc7,0xb7,0xb7,0xc8,0xc8,0xb8,0xb8, 0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xc6,0xc7,0xc7,0xc7,0xaa,0xc8,0xc8,0xc8,0xab,0xbc, 0xa8,0xa8,0xa8,0xc6,0xc6,0xa9,0xa9,0xc7,0xc7,0xaa,0xaa,0xaa,0xc8,0xc8,0xab,0xbc, 0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xba,0xba,0xaa,0xaa,0xaa,0xbb,0xbb,0xab,0xbc,0xbc, 0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xba,0xcb,0xaa,0xbb,0xbb,0xbb,0xcc,0xbc,0xbc, 0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xcb,0xcb,0xcb,0xbb,0xbb,0xcc,0xcc,0xcc,0xbc, 0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xae,0xcc,0xcc,0xcc,0xaf,0xaf, 0xbd,0xbd,0xbd,0xad,0xbe,0xbe,0xbe,0xbe,0xae,0xae,0xbf,0xbf,0xcc,0xaf,0xaf,0xb0, 0xbd,0xbd,0xbd,0xbe,0xbe,0xbe,0xbe,0xbe,0xbf,0xbf,0xbf,0xbf,0xbf,0xaf,0xb0,0xb0, 0xcd,0xcd,0xcd,0xce,0xce,0xce,0xb2,0xcf,0xcf,0xcf,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4, 0xcd,0xcd,0xcd,0xce,0xce,0xce,0xb2,0xcf,0xcf,0xcf,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4, 0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xb2,0xc3,0xc3,0xc3,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4, 0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xc2,0xc3,0xc3,0xc3,0xd4,0xc4,0xc4,0xc4,0xd5,0xd5, 0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xb6,0xc3,0xc3,0xc3,0xd4,0xc4,0xc4,0xc4,0xd5,0xb8, 0xc1,0xc1,0xc1,0xc2,0xc2,0xb6,0xb6,0xc3,0xc3,0xd4,0xb7,0xb7,0xc4,0xd5,0xd5,0xb8, 0xb5,0xb5,0xb5,0xc2,0xb6,0xb6,0xb6,0xb6,0xc3,0xd4,0xb7,0xb7,0xb7,0xd5,0xd5,0xb8, 0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xb6,0xc7,0xc7,0xc7,0xb7,0xc8,0xc8,0xc8,0xd9,0xd9, 0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xc6,0xc7,0xc7,0xc7,0xd8,0xc8,0xc8,0xc8,0xd9,0xd9, 0xc5,0xc5,0xc5,0xc6,0xc6,0xd7,0xd7,0xc7,0xc7,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xbc, 0xb9,0xb9,0xb9,0xd7,0xd7,0xba,0xba,0xba,0xd8,0xd8,0xbb,0xbb,0xbb,0xd9,0xd9,0xbc, 0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xcb,0xcb,0xcb,0xbb,0xbb,0xcc,0xcc,0xcc,0xbc, 0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xbb,0xcc,0xcc,0xcc,0xdd,0xdd, 0xc9,0xc9,0xc9,0xca,0xca,0xdb,0xdb,0xcb,0xcb,0xdc,0xdc,0xcc,0xcc,0xdd,0xdd,0xdd, 0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xb0, 0xbd,0xbd,0xbd,0xdb,0xbe,0xbe,0xbe,0xdc,0xdc,0xbf,0xbf,0xbf,0xdd,0xdd,0xb0,0xb0, 0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xcf,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2, 0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xcf,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2, 0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xc3,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2, 0xd2,0xd2,0xd2,0xc2,0xd3,0xd3,0xd3,0xc3,0xc3,0xd4,0xd4,0xc4,0xc4,0xd5,0xd5,0xe6, 0xd2,0xd2,0xd2,0xd3,0xd3,0xd3,0xd3,0xc3,0xd4,0xd4,0xd4,0xc4,0xc4,0xd5,0xd5,0xe6, 0xd2,0xd2,0xd2,0xd3,0xd3,0xd3,0xe4,0xc3,0xd4,0xd4,0xe5,0xc4,0xd5,0xd5,0xe6,0xe6, 0xe3,0xe3,0xe3,0xd3,0xd3,0xe4,0xb6,0xd4,0xd4,0xe5,0xe5,0xb7,0xd5,0xd5,0xe6,0xe6, 0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xd7,0xc7,0xc7,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xd9, 0xd6,0xd6,0xd6,0xc6,0xd7,0xd7,0xd7,0xc7,0xd8,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xea, 0xd6,0xd6,0xd6,0xd7,0xd7,0xd7,0xe8,0xd8,0xd8,0xd8,0xe9,0xc8,0xd9,0xd9,0xea,0xea, 0xe7,0xe7,0xe7,0xd7,0xd7,0xe8,0xe8,0xd8,0xd8,0xe9,0xe9,0xe9,0xd9,0xd9,0xea,0xea, 0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xe9,0xcc,0xcc,0xcc,0xea,0xea, 0xc9,0xc9,0xc9,0xca,0xca,0xdb,0xdb,0xcb,0xcb,0xdc,0xdc,0xcc,0xcc,0xdd,0xdd,0xdd, 0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xee, 0xda,0xda,0xda,0xdb,0xdb,0xec,0xec,0xdc,0xdc,0xed,0xed,0xed,0xdd,0xdd,0xee,0xee, 0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee, 0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2, 0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2, 0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2, 0xd2,0xd2,0xd2,0xd3,0xd3,0xe4,0xe4,0xd4,0xd4,0xd4,0xe5,0xe5,0xd5,0xd5,0xe6,0xe6, 0xe3,0xe3,0xe3,0xd3,0xe4,0xe4,0xe4,0xd4,0xd4,0xe5,0xe5,0xf6,0xd5,0xd5,0xe6,0xe6, 0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xe4,0xd4,0xe5,0xe5,0xe5,0xf6,0xd5,0xe6,0xe6,0xf7, 0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xd5,0xe6,0xe6,0xf7, 0xd6,0xd6,0xd6,0xd7,0xd7,0xd7,0xf5,0xc7,0xd8,0xd8,0xf6,0xc8,0xd9,0xd9,0xd9,0xf7, 0xd6,0xd6,0xd6,0xd7,0xd7,0xe8,0xe8,0xd8,0xd8,0xd8,0xe9,0xe9,0xd9,0xd9,0xea,0xea, 0xe7,0xe7,0xe7,0xd7,0xe8,0xe8,0xe8,0xd8,0xd8,0xe9,0xe9,0xe9,0xd9,0xea,0xea,0xea, 0xe7,0xe7,0xe7,0xe8,0xe8,0xe8,0xf9,0xf9,0xe9,0xe9,0xe9,0xfa,0xd9,0xea,0xea,0xfb, 0xf8,0xf8,0xf8,0xe8,0xf9,0xf9,0xf9,0xcb,0xe9,0xe9,0xfa,0xfa,0xcc,0xea,0xea,0xfb, 0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xee, 0xda,0xda,0xda,0xdb,0xdb,0xec,0xec,0xdc,0xdc,0xed,0xed,0xed,0xdd,0xdd,0xee,0xee, 0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee, 0xeb,0xeb,0xeb,0xec,0xec,0xfd,0xfd,0xfd,0xed,0xed,0xfe,0xfe,0xee,0xee,0xee,0xff, 0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3, 0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3, 0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3, 0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xd5,0xe6,0xe6,0xf7, 0xf4,0xf4,0xf4,0xe4,0xe4,0xf5,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xf6,0xe6,0xe6,0xf7, 0xf4,0xf4,0xf4,0xe4,0xf5,0xf5,0xf5,0xf5,0xe5,0xf6,0xf6,0xf6,0xf6,0xe6,0xf7,0xf7, 0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5,0xe5,0xf6,0xf6,0xf6,0xf6,0xe6,0xf7,0xf7, 0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5,0xd8,0xf6,0xf6,0xf6,0xd9,0xd9,0xf7,0xf7, 0xe7,0xe7,0xe7,0xe8,0xe8,0xe8,0xe8,0xd8,0xe9,0xe9,0xe9,0xfa,0xd9,0xea,0xea,0xea, 0xf8,0xf8,0xf8,0xe8,0xe8,0xf9,0xf9,0xf9,0xe9,0xe9,0xfa,0xfa,0xfa,0xea,0xea,0xfb, 0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xf9,0xe9,0xfa,0xfa,0xfa,0xfa,0xea,0xfb,0xfb, 0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfa,0xfa,0xea,0xfb,0xfb, 0xf8,0xf8,0xf8,0xdb,0xf9,0xf9,0xf9,0xdc,0xdc,0xfa,0xfa,0xfa,0xdd,0xdd,0xee,0xfb, 0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee, 0xeb,0xeb,0xeb,0xec,0xec,0xfd,0xfd,0xfd,0xed,0xed,0xfe,0xfe,0xee,0xee,0xee,0xff, 0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfd,0xed,0xfe,0xfe,0xfe,0xfe,0xee,0xff,0xff, } }; Memcmap *memdefcmap = &def; void _memmkcmap(void){} drawterm-20170818/libmemdraw/cread.c000066400000000000000000000036761314554504700172040ustar00rootroot00000000000000#include #include #include #include Memimage* creadmemimage(int fd) { char hdr[5*12+1]; Rectangle r; int m, nb, miny, maxy, new, ldepth, ncblock; uchar *buf; Memimage *i; ulong chan; if(readn(fd, hdr, 5*12) != 5*12){ werrstr("readmemimage: short header (2)"); return nil; } /* * distinguish new channel descriptor from old ldepth. * channel descriptors have letters as well as numbers, * while ldepths are a single digit formatted as %-11d. */ new = 0; for(m=0; m<10; m++){ if(hdr[m] != ' '){ new = 1; break; } } if(hdr[11] != ' '){ werrstr("creadimage: bad format"); return nil; } if(new){ hdr[11] = '\0'; if((chan = strtochan(hdr)) == 0){ werrstr("creadimage: bad channel string %s", hdr); return nil; } }else{ ldepth = ((int)hdr[10])-'0'; if(ldepth<0 || ldepth>3){ werrstr("creadimage: bad ldepth %d", ldepth); return nil; } chan = drawld2chan[ldepth]; } r.min.x=atoi(hdr+1*12); r.min.y=atoi(hdr+2*12); r.max.x=atoi(hdr+3*12); r.max.y=atoi(hdr+4*12); if(r.min.x>r.max.x || r.min.y>r.max.y){ werrstr("creadimage: bad rectangle"); return nil; } i = allocmemimage(r, chan); if(i == nil) return nil; ncblock = _compblocksize(r, i->depth); buf = malloc(ncblock); if(buf == nil) goto Errout; miny = r.min.y; while(miny != r.max.y){ if(readn(fd, hdr, 2*12) != 2*12){ Shortread: werrstr("readmemimage: short read"); Errout: freememimage(i); free(buf); return nil; } maxy = atoi(hdr+0*12); nb = atoi(hdr+1*12); if(maxy<=miny || r.max.y #include #include #include Memsubfont* getmemdefont(void) { char *hdr, *p; int n; Fontchar *fc; Memsubfont *f; int ld; Rectangle r; Memdata *md; Memimage *i; /* * make sure data is word-aligned. this is true with Plan 9 compilers * but not in general. the byte order is right because the data is * declared as char*, not ulong*. */ p = (char*)defontdata; n = (uintptr)p & 3; if(n != 0){ memmove(p+(4-n), p, sizeofdefont-n); p += 4-n; } ld = atoi(p+0*12); r.min.x = atoi(p+1*12); r.min.y = atoi(p+2*12); r.max.x = atoi(p+3*12); r.max.y = atoi(p+4*12); md = mallocz(sizeof(Memdata), 1); if(md == nil) return nil; p += 5*12; md->base = nil; /* so freememimage doesn't free p */ md->bdata = (uchar*)p; /* ick */ md->ref = 1; md->allocd = 1; /* so freememimage does free md */ i = allocmemimaged(r, drawld2chan[ld], md, nil); if(i == nil){ free(md); return nil; } hdr = p+Dy(r)*i->width*sizeof(ulong); n = atoi(hdr); p = hdr+3*12; fc = malloc(sizeof(Fontchar)*(n+1)); if(fc == 0){ freememimage(i); return 0; } _unpackinfo(fc, (uchar*)p, n); f = allocmemsubfont("*default*", n, atoi(hdr+12), atoi(hdr+24), fc, i); if(f == 0){ freememimage(i); free(fc); return 0; } return f; } drawterm-20170818/libmemdraw/draw.c000066400000000000000000001556431314554504700170650ustar00rootroot00000000000000#include #include #include #include int drawdebug; static int tablesbuilt; /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */ #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19) /* * For 16-bit values, x / 255 == (t = x+1, (t+(t>>8)) >> 8). * We add another 127 to round to the nearest value rather * than truncate. * * CALCxy does x bytewise calculations on y input images (x=1,4; y=1,2). * CALC2x does two parallel 16-bit calculations on y input images (y=1,2). */ #define CALC11(a, v, tmp) \ (tmp=(a)*(v)+128, (tmp+(tmp>>8))>>8) #define CALC12(a1, v1, a2, v2, tmp) \ (tmp=(a1)*(v1)+(a2)*(v2)+128, (tmp+(tmp>>8))>>8) #define MASK 0xFF00FF #define CALC21(a, vvuu, tmp) \ (tmp=(a)*(vvuu)+0x00800080, ((tmp+((tmp>>8)&MASK))>>8)&MASK) #define CALC41(a, rgba, tmp1, tmp2) \ (CALC21(a, rgba & MASK, tmp1) | \ (CALC21(a, (rgba>>8)&MASK, tmp2)<<8)) #define CALC22(a1, vvuu1, a2, vvuu2, tmp) \ (tmp=(a1)*(vvuu1)+(a2)*(vvuu2)+0x00800080, ((tmp+((tmp>>8)&MASK))>>8)&MASK) #define CALC42(a1, rgba1, a2, rgba2, tmp1, tmp2) \ (CALC22(a1, rgba1 & MASK, a2, rgba2 & MASK, tmp1) | \ (CALC22(a1, (rgba1>>8) & MASK, a2, (rgba2>>8) & MASK, tmp2)<<8)) static void mktables(void); typedef int Subdraw(Memdrawparam*); static Subdraw chardraw, alphadraw, memoptdraw; static Memimage* memones; static Memimage* memzeros; Memimage *memwhite; Memimage *memblack; Memimage *memtransparent; Memimage *memopaque; int _ifmt(Fmt*); void _memimageinit(void) { static int didinit = 0; if(didinit) return; didinit = 1; mktables(); _memmkcmap(); fmtinstall('R', Rfmt); fmtinstall('P', Pfmt); memones = allocmemimage(Rect(0,0,1,1), GREY1); memones->flags |= Frepl; memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); *byteaddr(memones, ZP) = ~0; memzeros = allocmemimage(Rect(0,0,1,1), GREY1); memzeros->flags |= Frepl; memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); *byteaddr(memzeros, ZP) = 0; if(memones == nil || memzeros == nil) assert(0 /*cannot initialize memimage library */); /* RSC BUG */ memwhite = memones; memblack = memzeros; memopaque = memones; memtransparent = memzeros; } ulong _imgtorgba(Memimage*, ulong); ulong _rgbatoimg(Memimage*, ulong); ulong _pixelbits(Memimage*, Point); #define DBG if(0) static Memdrawparam par; Memdrawparam* _memimagedrawsetup(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op) { if(mask == nil) mask = memopaque; DBG print("memimagedraw %p/%luX %R @ %p %p/%luX %P %p/%luX %P... ", dst, dst->chan, r, dst->data->bdata, src, src->chan, p0, mask, mask->chan, p1); if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){ // if(drawdebug) // iprint("empty clipped rectangle\n"); return nil; } if(op < Clear || op > SoverD){ // if(drawdebug) // iprint("op out of range: %d\n", op); return nil; } par.op = op; par.dst = dst; par.r = r; par.src = src; /* par.sr set by drawclip */ par.mask = mask; /* par.mr set by drawclip */ par.state = 0; if(src->flags&Frepl){ par.state |= Replsrc; if(Dx(src->r)==1 && Dy(src->r)==1){ par.sval = _pixelbits(src, src->r.min); par.state |= Simplesrc; par.srgba = _imgtorgba(src, par.sval); par.sdval = _rgbatoimg(dst, par.srgba); if((par.srgba&0xFF) == 0 && (op&DoutS)){ // if (drawdebug) iprint("fill with transparent source\n"); return nil; /* no-op successfully handled */ } } } if(mask->flags & Frepl){ par.state |= Replmask; if(Dx(mask->r)==1 && Dy(mask->r)==1){ par.mval = _pixelbits(mask, mask->r.min); if(par.mval == 0 && (op&DoutS)){ // if(drawdebug) iprint("fill with zero mask\n"); return nil; /* no-op successfully handled */ } par.state |= Simplemask; if(par.mval == ~0) par.state |= Fullmask; par.mrgba = _imgtorgba(mask, par.mval); } } // if(drawdebug) // iprint("dr %R sr %R mr %R...", r, par.sr, par.mr); DBG print("draw dr %R sr %R mr %R %lux\n", r, par.sr, par.mr, par.state); return ∥ } void _memimagedraw(Memdrawparam *par) { if (par == nil) return; /* * Now that we've clipped the parameters down to be consistent, we * simply try sub-drawing routines in order until we find one that was able * to handle us. If the sub-drawing routine returns zero, it means it was * unable to satisfy the request, so we do not return. */ /* * Hardware support. Each video driver provides this function, * which checks to see if there is anything it can help with. * There could be an if around this checking to see if dst is in video memory. */ DBG print("test hwdraw\n"); if(hwdraw(par)){ //if(drawdebug) iprint("hw handled\n"); DBG print("hwdraw handled\n"); return; } /* * Optimizations using memmove and memset. */ DBG print("test memoptdraw\n"); if(memoptdraw(par)){ //if(drawdebug) iprint("memopt handled\n"); DBG print("memopt handled\n"); return; } /* * Character drawing. * Solid source color being painted through a boolean mask onto a high res image. */ DBG print("test chardraw\n"); if(chardraw(par)){ //if(drawdebug) iprint("chardraw handled\n"); DBG print("chardraw handled\n"); return; } /* * General calculation-laden case that does alpha for each pixel. */ DBG print("do alphadraw\n"); alphadraw(par); //if(drawdebug) iprint("alphadraw handled\n"); DBG print("alphadraw handled\n"); } #undef DBG /* * Clip the destination rectangle further based on the properties of the * source and mask rectangles. Once the destination rectangle is properly * clipped, adjust the source and mask rectangles to be the same size. * Then if source or mask is replicated, move its clipped rectangle * so that its minimum point falls within the repl rectangle. * * Return zero if the final rectangle is null. */ int drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr) { Point rmin, delta; int splitcoords; Rectangle omr; if(r->min.x>=r->max.x || r->min.y>=r->max.y) return 0; splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y); /* clip to destination */ rmin = r->min; if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr)) return 0; /* move mask point */ p1->x += r->min.x-rmin.x; p1->y += r->min.y-rmin.y; /* move source point */ p0->x += r->min.x-rmin.x; p0->y += r->min.y-rmin.y; /* map destination rectangle into source */ sr->min = *p0; sr->max.x = p0->x+Dx(*r); sr->max.y = p0->y+Dy(*r); /* sr is r in source coordinates; clip to source */ if(!(src->flags&Frepl) && !rectclip(sr, src->r)) return 0; if(!rectclip(sr, src->clipr)) return 0; /* compute and clip rectangle in mask */ if(splitcoords){ /* move mask point with source */ p1->x += sr->min.x-p0->x; p1->y += sr->min.y-p0->y; mr->min = *p1; mr->max.x = p1->x+Dx(*sr); mr->max.y = p1->y+Dy(*sr); omr = *mr; /* mr is now rectangle in mask; clip it */ if(!(mask->flags&Frepl) && !rectclip(mr, mask->r)) return 0; if(!rectclip(mr, mask->clipr)) return 0; /* reflect any clips back to source */ sr->min.x += mr->min.x-omr.min.x; sr->min.y += mr->min.y-omr.min.y; sr->max.x += mr->max.x-omr.max.x; sr->max.y += mr->max.y-omr.max.y; *p1 = mr->min; }else{ if(!(mask->flags&Frepl) && !rectclip(sr, mask->r)) return 0; if(!rectclip(sr, mask->clipr)) return 0; *p1 = sr->min; } /* move source clipping back to destination */ delta.x = r->min.x - p0->x; delta.y = r->min.y - p0->y; r->min.x = sr->min.x + delta.x; r->min.y = sr->min.y + delta.y; r->max.x = sr->max.x + delta.x; r->max.y = sr->max.y + delta.y; /* move source rectangle so sr->min is in src->r */ if(src->flags&Frepl) { delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x; delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y; sr->min.x += delta.x; sr->min.y += delta.y; sr->max.x += delta.x; sr->max.y += delta.y; } *p0 = sr->min; /* move mask point so it is in mask->r */ *p1 = drawrepl(mask->r, *p1); mr->min = *p1; mr->max.x = p1->x+Dx(*sr); mr->max.y = p1->y+Dy(*sr); assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r)); assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r)); assert(ptinrect(*p0, src->r)); assert(ptinrect(*p1, mask->r)); assert(ptinrect(r->min, dst->r)); return 1; } /* * Conversion tables. */ static uchar replbit[1+8][256]; /* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */ static uchar conv18[256][8]; /* conv18[x][y] is the yth pixel in the depth-1 pixel x */ static uchar conv28[256][4]; /* ... */ static uchar conv48[256][2]; /* * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8. * the X's are where to put the bottom (ones) bit of the n-bit pattern. * only the top 8 bits of the result are actually used. * (the lower 8 bits are needed to get bits in the right place * when n is not a divisor of 8.) * * Should check to see if its easier to just refer to replmul than * use the precomputed values in replbit. On PCs it may well * be; on machines with slow multiply instructions it probably isn't. */ #define a ((((((((((((((((0 #define X *2+1) #define _ *2) static int replmul[1+8] = { 0, a X X X X X X X X X X X X X X X X, a _ X _ X _ X _ X _ X _ X _ X _ X, a _ _ X _ _ X _ _ X _ _ X _ _ X _, a _ _ _ X _ _ _ X _ _ _ X _ _ _ X, a _ _ _ _ X _ _ _ _ X _ _ _ _ X _, a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _, a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _, a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X, }; #undef a #undef X #undef _ static void mktables(void) { int i, j, mask, sh, small; if(tablesbuilt) return; fmtinstall('R', Rfmt); fmtinstall('P', Pfmt); tablesbuilt = 1; /* bit replication up to 8 bits */ for(i=0; i<256; i++){ for(j=0; j<=8; j++){ /* j <= 8 [sic] */ small = i & ((1<>8; } } /* bit unpacking up to 8 bits, only powers of 2 */ for(i=0; i<256; i++){ for(j=0, sh=7, mask=1; j<8; j++, sh--) conv18[i][j] = replbit[1][(i>>sh)&mask]; for(j=0, sh=6, mask=3; j<4; j++, sh-=2) conv28[i][j] = replbit[2][(i>>sh)&mask]; for(j=0, sh=4, mask=15; j<2; j++, sh-=4) conv48[i][j] = replbit[4][(i>>sh)&mask]; } } static uchar ones = 0xff; /* * General alpha drawing case. Can handle anything. */ typedef struct Buffer Buffer; struct Buffer { /* used by most routines */ uchar *red; uchar *grn; uchar *blu; uchar *alpha; uchar *grey; ulong *rgba; int delta; /* number of bytes to add to pointer to get next pixel to the right */ /* used by boolcalc* for mask data */ uchar *m; /* ptr to mask data r.min byte; like p->bytermin */ int mskip; /* no. of left bits to skip in *m */ uchar *bm; /* ptr to mask data img->r.min byte; like p->bytey0s */ int bmskip; /* no. of left bits to skip in *bm */ uchar *em; /* ptr to mask data img->r.max.x byte; like p->bytey0e */ int emskip; /* no. of right bits to skip in *em */ }; typedef struct Param Param; typedef Buffer Readfn(Param*, uchar*, int); typedef void Writefn(Param*, uchar*, Buffer); typedef Buffer Calcfn(Buffer, Buffer, Buffer, int, int, int); enum { MAXBCACHE = 16 }; /* giant rathole to customize functions with */ struct Param { Readfn *replcall; Readfn *greymaskcall; Readfn *convreadcall; Writefn *convwritecall; Memimage *img; Rectangle r; int dx; /* of r */ int needbuf; int convgrey; int alphaonly; uchar *bytey0s; /* byteaddr(Pt(img->r.min.x, img->r.min.y)) */ uchar *bytermin; /* byteaddr(Pt(r.min.x, img->r.min.y)) */ uchar *bytey0e; /* byteaddr(Pt(img->r.max.x, img->r.min.y)) */ int bwidth; int replcache; /* if set, cache buffers */ Buffer bcache[MAXBCACHE]; ulong bfilled; uchar *bufbase; int bufoff; int bufdelta; int dir; int convbufoff; uchar *convbuf; Param *convdpar; int convdx; }; static uchar *drawbuf; static int ndrawbuf; static int mdrawbuf; static Param spar, mpar, dpar; /* easier on the stacks */ static Readfn greymaskread, replread, readptr; static Writefn nullwrite; static Calcfn alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS; static Calcfn boolcalc14, boolcalc236789, boolcalc1011; static Readfn* readfn(Memimage*); static Readfn* readalphafn(Memimage*); static Writefn* writefn(Memimage*); static Calcfn* boolcopyfn(Memimage*, Memimage*); static Readfn* convfn(Memimage*, Param*, Memimage*, Param*); static Calcfn *alphacalc[Ncomp] = { alphacalc0, /* Clear */ alphacalc14, /* DoutS */ alphacalc2810, /* SoutD */ alphacalc3679, /* DxorS */ alphacalc14, /* DinS */ alphacalc5, /* D */ alphacalc3679, /* DatopS */ alphacalc3679, /* DoverS */ alphacalc2810, /* SinD */ alphacalc3679, /* SatopD */ alphacalc2810, /* S */ alphacalc11, /* SoverD */ }; static Calcfn *boolcalc[Ncomp] = { alphacalc0, /* Clear */ boolcalc14, /* DoutS */ boolcalc236789, /* SoutD */ boolcalc236789, /* DxorS */ boolcalc14, /* DinS */ alphacalc5, /* D */ boolcalc236789, /* DatopS */ boolcalc236789, /* DoverS */ boolcalc236789, /* SinD */ boolcalc236789, /* SatopD */ boolcalc1011, /* S */ boolcalc1011, /* SoverD */ }; static int allocdrawbuf(void) { uchar *p; if(ndrawbuf > mdrawbuf){ p = realloc(drawbuf, ndrawbuf); if(p == nil){ werrstr("memimagedraw out of memory"); return -1; } drawbuf = p; mdrawbuf = ndrawbuf; } return 0; } static Param getparam(Memimage *img, Rectangle r, int convgrey, int needbuf) { Param p; int nbuf; memset(&p, 0, sizeof p); p.img = img; p.r = r; p.dx = Dx(r); p.needbuf = needbuf; p.convgrey = convgrey; assert(img->r.min.x <= r.min.x && r.min.x < img->r.max.x); p.bytey0s = byteaddr(img, Pt(img->r.min.x, img->r.min.y)); p.bytermin = byteaddr(img, Pt(r.min.x, img->r.min.y)); p.bytey0e = byteaddr(img, Pt(img->r.max.x, img->r.min.y)); p.bwidth = sizeof(ulong)*img->width; assert(p.bytey0s <= p.bytermin && p.bytermin <= p.bytey0e); if(p.r.min.x == p.img->r.min.x) assert(p.bytermin == p.bytey0s); nbuf = 1; if((img->flags&Frepl) && Dy(img->r) <= MAXBCACHE && Dy(img->r) < Dy(r)){ p.replcache = 1; nbuf = Dy(img->r); } p.bufdelta = 4*p.dx; p.bufoff = ndrawbuf; ndrawbuf += p.bufdelta*nbuf; return p; } static void clipy(Memimage *img, int *y) { int dy; dy = Dy(img->r); if(*y == dy) *y = 0; else if(*y == -1) *y = dy-1; assert(0 <= *y && *y < dy); } static void dumpbuf(char *s, Buffer b, int n) { int i; uchar *p; print("%s", s); for(i=0; ir; dx = Dx(r); dy = Dy(r); ndrawbuf = 0; src = par->src; mask = par->mask; dst = par->dst; sr = par->sr; mr = par->mr; op = par->op; isgrey = dst->flags&Fgrey; /* * Buffering when src and dst are the same bitmap is sufficient but not * necessary. There are stronger conditions we could use. We could * check to see if the rectangles intersect, and if simply moving in the * correct y direction can avoid the need to buffer. */ needbuf = (src->data == dst->data); spar = getparam(src, sr, isgrey, needbuf); dpar = getparam(dst, r, isgrey, needbuf); mpar = getparam(mask, mr, 0, needbuf); dir = (needbuf && byteaddr(dst, r.min) > byteaddr(src, sr.min)) ? -1 : 1; spar.dir = mpar.dir = dpar.dir = dir; /* * If the mask is purely boolean, we can convert from src to dst format * when we read src, and then just copy it to dst where the mask tells us to. * This requires a boolean (1-bit grey) mask and lack of a source alpha channel. * * The computation is accomplished by assigning the function pointers as follows: * rdsrc - read and convert source into dst format in a buffer * rdmask - convert mask to bytes, set pointer to it * rddst - fill with pointer to real dst data, but do no reads * calc - copy src onto dst when mask says to. * wrdst - do nothing * This is slightly sleazy, since things aren't doing exactly what their names say, * but it avoids a fair amount of code duplication to make this a case here * rather than have a separate booldraw. */ //if(drawdebug) iprint("flag %lud mchan %lux=?%x dd %d\n", src->flags&Falpha, mask->chan, GREY1, dst->depth); if(!(src->flags&Falpha) && mask->chan == GREY1 && dst->depth >= 8 && op == SoverD){ //if(drawdebug) iprint("boolcopy..."); rdsrc = convfn(dst, &dpar, src, &spar); rddst = readptr; rdmask = readfn(mask); calc = boolcopyfn(dst, mask); wrdst = nullwrite; }else{ /* usual alphadraw parameter fetching */ rdsrc = readfn(src); rddst = readfn(dst); wrdst = writefn(dst); calc = alphacalc[op]; /* * If there is no alpha channel, we'll ask for a grey channel * and pretend it is the alpha. */ if(mask->flags&Falpha){ rdmask = readalphafn(mask); mpar.alphaonly = 1; }else{ mpar.greymaskcall = readfn(mask); mpar.convgrey = 1; rdmask = greymaskread; /* * Should really be above, but then boolcopyfns would have * to deal with bit alignment, and I haven't written that. * * This is a common case for things like ellipse drawing. * When there's no alpha involved and the mask is boolean, * we can avoid all the division and multiplication. */ if(mask->chan == GREY1 && !(src->flags&Falpha)) calc = boolcalc[op]; else if(op == SoverD && !(src->flags&Falpha)) calc = alphacalcS; } } /* * If the image has a small enough repl rectangle, * we can just read each line once and cache them. */ if(spar.replcache){ spar.replcall = rdsrc; rdsrc = replread; } if(mpar.replcache){ mpar.replcall = rdmask; rdmask = replread; } if(allocdrawbuf() < 0) return 0; /* * Before we were saving only offsets from drawbuf in the parameter * structures; now that drawbuf has been grown to accomodate us, * we can fill in the pointers. */ spar.bufbase = drawbuf+spar.bufoff; mpar.bufbase = drawbuf+mpar.bufoff; dpar.bufbase = drawbuf+dpar.bufoff; spar.convbuf = drawbuf+spar.convbufoff; if(dir == 1){ starty = 0; endy = dy; }else{ starty = dy-1; endy = -1; } /* * srcy, masky, and dsty are offsets from the top of their * respective Rectangles. they need to be contained within * the rectangles, so clipy can keep them there without division. */ srcy = (starty + sr.min.y - src->r.min.y)%Dy(src->r); masky = (starty + mr.min.y - mask->r.min.y)%Dy(mask->r); dsty = starty + r.min.y - dst->r.min.y; assert(0 <= srcy && srcy < Dy(src->r)); assert(0 <= masky && masky < Dy(mask->r)); assert(0 <= dsty && dsty < Dy(dst->r)); for(y=starty; y!=endy; y+=dir, srcy+=dir, masky+=dir, dsty+=dir){ clipy(src, &srcy); clipy(dst, &dsty); clipy(mask, &masky); bsrc = rdsrc(&spar, spar.bufbase, srcy); DBG print("["); bmask = rdmask(&mpar, mpar.bufbase, masky); DBG print("]\n"); bdst = rddst(&dpar, dpar.bufbase, dsty); DBG dumpbuf("src", bsrc, dx); DBG dumpbuf("mask", bmask, dx); DBG dumpbuf("dst", bdst, dx); bdst = calc(bdst, bsrc, bmask, dx, isgrey, op); wrdst(&dpar, dpar.bytermin+dsty*dpar.bwidth, bdst); } return 1; } #undef DBG static Buffer alphacalc0(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op) { USED(grey); USED(op); memset(bdst.rgba, 0, dx*bdst.delta); return bdst; } /* * Do the channels in the buffers match enough * that we can do word-at-a-time operations * on the pixels? */ static int chanmatch(Buffer *bdst, Buffer *bsrc) { uchar *drgb, *srgb; /* * first, r, g, b must be in the same place * in the rgba word. */ drgb = (uchar*)bdst->rgba; srgb = (uchar*)bsrc->rgba; if(bdst->red - drgb != bsrc->red - srgb || bdst->blu - drgb != bsrc->blu - srgb || bdst->grn - drgb != bsrc->grn - srgb) return 0; /* * that implies alpha is in the same place, * if it is there at all (it might be == &ones). * if the destination is &ones, we can scribble * over the rgba slot just fine. */ if(bdst->alpha == &ones) return 1; /* * if the destination is not ones but the src is, * then the simultaneous calculation will use * bogus bytes from the src's rgba. no good. */ if(bsrc->alpha == &ones) return 0; /* * otherwise, alphas are in the same place. */ return 1; } static Buffer alphacalc14(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op) { Buffer obdst; int fd, sadelta; int i, sa, ma, q; ulong t, t1; obdst = bdst; sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta; q = bsrc.delta == 4 && bdst.delta == 4 && chanmatch(&bdst, &bsrc); for(i=0; ibcache[y]; if((p->bfilled & (1<bfilled |= 1<replcall(p, p->bufbase+y*p->bufdelta, y); } return *b; } /* * Alpha reading function that simply relabels the grey pointer. */ static Buffer greymaskread(Param *p, uchar *buf, int y) { Buffer b; b = p->greymaskcall(p, buf, y); b.alpha = b.grey; return b; } #define DBG if(0) static Buffer readnbit(Param *p, uchar *buf, int y) { Buffer b; Memimage *img; uchar *repl, *r, *w, *ow, bits; int i, n, sh, depth, x, dx, npack, nbits; b.rgba = (ulong*)buf; b.grey = w = buf; b.red = b.blu = b.grn = w; b.alpha = &ones; b.delta = 1; dx = p->dx; img = p->img; depth = img->depth; repl = &replbit[depth][0]; npack = 8/depth; sh = 8-depth; /* copy from p->r.min.x until end of repl rectangle */ x = p->r.min.x; n = dx; if(n > p->img->r.max.x - x) n = p->img->r.max.x - x; r = p->bytermin + y*p->bwidth; DBG print("readnbit dx %d %p=%p+%d*%d, *r=%d fetch %d ", dx, r, p->bytermin, y, p->bwidth, *r, n); bits = *r++; nbits = 8; if((i=x&(npack-1))){ DBG print("throwaway %d...", i); bits <<= depth*i; nbits -= depth*i; } for(i=0; i>sh]; DBG print("bit %x...", repl[bits>>sh]); bits <<= depth; nbits -= depth; } dx -= n; if(dx == 0) return b; assert(x+i == p->img->r.max.x); /* copy from beginning of repl rectangle until where we were before. */ x = p->img->r.min.x; n = dx; if(n > p->r.min.x - x) n = p->r.min.x - x; r = p->bytey0s + y*p->bwidth; DBG print("x=%d r=%p...", x, r); bits = *r++; nbits = 8; if((i=x&(npack-1))){ bits <<= depth*i; nbits -= depth*i; } DBG print("nbits=%d...", nbits); for(i=0; i>sh]; DBG print("bit %x...", repl[bits>>sh]); bits <<= depth; nbits -= depth; DBG print("bits %x nbits %d...", bits, nbits); } dx -= n; if(dx == 0) return b; assert(dx > 0); /* now we have exactly one full scan line: just replicate the buffer itself until we are done */ ow = buf; while(dx--) *w++ = *ow++; return b; } #undef DBG #define DBG if(0) static void writenbit(Param *p, uchar *w, Buffer src) { uchar *r; ulong bits; int i, sh, depth, npack, nbits, x, ex; assert(src.grey != nil && src.delta == 1); x = p->r.min.x; ex = x+p->dx; depth = p->img->depth; npack = 8/depth; i=x&(npack-1); bits = i ? (*w >> (8-depth*i)) : 0; nbits = depth*i; sh = 8-depth; r = src.grey; for(; x> sh); nbits += depth; if(nbits == 8){ *w++ = bits; nbits = 0; } } if(nbits){ sh = 8-nbits; bits <<= sh; bits |= *w & ((1<bytey0s + y*p->bwidth; r = p->bytermin + y*p->bwidth; end = p->bytey0e + y*p->bwidth; cmap = p->img->cmap->cmap2rgb; convgrey = p->convgrey; copyalpha = (p->img->flags&Falpha) ? 1 : 0; w = buf; dx = p->dx; if(copyalpha){ b.alpha = buf++; a = p->img->shift[CAlpha]/8; m = p->img->shift[CMap]/8; for(i=0; iimg->cmap->rgb2cmap; delta = src.delta; red= src.red; grn = src.grn; blu = src.blu; dx = p->dx; for(i=0; i>4)*256+(*grn>>4)*16+(*blu>>4)]; } #define DBG if(0) static Buffer readbyte(Param *p, uchar *buf, int y) { Buffer b; Memimage *img; int dx, isgrey, convgrey, alphaonly, copyalpha, i, nb; uchar *begin, *end, *r, *w, *rrepl, *grepl, *brepl, *arepl, *krepl; uchar ured, ugrn, ublu; ulong u; img = p->img; begin = p->bytey0s + y*p->bwidth; r = p->bytermin + y*p->bwidth; end = p->bytey0e + y*p->bwidth; w = buf; dx = p->dx; nb = img->depth/8; convgrey = p->convgrey; /* convert rgb to grey */ isgrey = img->flags&Fgrey; alphaonly = p->alphaonly; copyalpha = (img->flags&Falpha) ? 1 : 0; DBG print("copyalpha %d alphaonly %d convgrey %d isgrey %d\n", copyalpha, alphaonly, convgrey, isgrey); /* if we can, avoid processing everything */ if(!(img->flags&Frepl) && !convgrey && (img->flags&Fbytes)){ memset(&b, 0, sizeof b); if(p->needbuf){ memmove(buf, r, dx*nb); r = buf; } b.rgba = (ulong*)r; if(copyalpha) b.alpha = r+img->shift[CAlpha]/8; else b.alpha = &ones; if(isgrey){ b.grey = r+img->shift[CGrey]/8; b.red = b.grn = b.blu = b.grey; }else{ b.red = r+img->shift[CRed]/8; b.grn = r+img->shift[CGreen]/8; b.blu = r+img->shift[CBlue]/8; } b.delta = nb; return b; } DBG print("2\n"); rrepl = replbit[img->nbits[CRed]]; grepl = replbit[img->nbits[CGreen]]; brepl = replbit[img->nbits[CBlue]]; arepl = replbit[img->nbits[CAlpha]]; krepl = replbit[img->nbits[CGrey]]; for(i=0; i>img->shift[CAlpha]) & img->mask[CAlpha]]; DBG print("a %x\n", w[-1]); } if(isgrey) *w++ = krepl[(u >> img->shift[CGrey]) & img->mask[CGrey]]; else if(!alphaonly){ ured = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]]; ugrn = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]]; ublu = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]]; if(convgrey){ DBG print("g %x %x %x\n", ured, ugrn, ublu); *w++ = RGB2K(ured, ugrn, ublu); DBG print("%x\n", w[-1]); }else{ *w++ = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]]; *w++ = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]]; *w++ = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]]; } } r += nb; if(r == end) r = begin; } b.alpha = copyalpha ? buf : &ones; b.rgba = (ulong*)buf; if(alphaonly){ b.red = b.grn = b.blu = b.grey = nil; if(!copyalpha) b.rgba = nil; b.delta = 1; }else if(isgrey || convgrey){ b.grey = buf+copyalpha; b.red = b.grn = b.blu = buf+copyalpha; b.delta = copyalpha+1; DBG print("alpha %x grey %x\n", b.alpha ? *b.alpha : 0xFF, *b.grey); }else{ b.blu = buf+copyalpha; b.grn = buf+copyalpha+1; b.grey = nil; b.red = buf+copyalpha+2; b.delta = copyalpha+3; } return b; } #undef DBG #define DBG if(0) static void writebyte(Param *p, uchar *w, Buffer src) { Memimage *img; int i, isalpha, isgrey, nb, delta, dx, adelta; uchar ff, *red, *grn, *blu, *grey, *alpha; ulong u, mask; img = p->img; red = src.red; grn = src.grn; blu = src.blu; alpha = src.alpha; delta = src.delta; grey = src.grey; dx = p->dx; nb = img->depth/8; mask = (nb==4) ? 0 : ~((1<depth)-1); isalpha = img->flags&Falpha; isgrey = img->flags&Fgrey; adelta = src.delta; if(isalpha && (alpha == nil || alpha == &ones)){ ff = 0xFF; alpha = &ff; adelta = 0; } for(i=0; i> (8-img->nbits[CGrey])) & img->mask[CGrey]) << img->shift[CGrey]; DBG print("|grey %.8lux...", u); grey += delta; }else{ u |= ((*red >> (8-img->nbits[CRed])) & img->mask[CRed]) << img->shift[CRed]; u |= ((*grn >> (8-img->nbits[CGreen])) & img->mask[CGreen]) << img->shift[CGreen]; u |= ((*blu >> (8-img->nbits[CBlue])) & img->mask[CBlue]) << img->shift[CBlue]; red += delta; grn += delta; blu += delta; DBG print("|rgb %.8lux...", u); } if(isalpha){ u |= ((*alpha >> (8-img->nbits[CAlpha])) & img->mask[CAlpha]) << img->shift[CAlpha]; alpha += adelta; DBG print("|alpha %.8lux...", u); } w[0] = u; w[1] = u>>8; w[2] = u>>16; w[3] = u>>24; w += nb; } } #undef DBG static Readfn* readfn(Memimage *img) { if(img->depth < 8) return readnbit; if(img->nbits[CMap] == 8) return readcmap; return readbyte; } static Readfn* readalphafn(Memimage *m) { USED(m); return readbyte; } static Writefn* writefn(Memimage *img) { if(img->depth < 8) return writenbit; if(img->chan == CMAP8) return writecmap; return writebyte; } static void nullwrite(Param *p, uchar *s, Buffer b) { USED(p); USED(s); } static Buffer readptr(Param *p, uchar *s, int y) { Buffer b; uchar *q; USED(s); q = p->bytermin + y*p->bwidth; b.red = q; /* ptr to data */ b.grn = b.blu = b.grey = b.alpha = nil; b.rgba = (ulong*)q; b.delta = p->img->depth/8; return b; } static Buffer boolmemmove(Buffer bdst, Buffer bsrc, Buffer b1, int dx, int i, int o) { USED(i); USED(o); memmove(bdst.red, bsrc.red, dx*bdst.delta); return bdst; } static Buffer boolcopy8(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o) { uchar *m, *r, *w, *ew; USED(i); USED(o); m = bmask.grey; w = bdst.red; r = bsrc.red; ew = w+dx; for(; w < ew; w++,r++) if(*m++) *w = *r; return bdst; /* not used */ } static Buffer boolcopy16(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o) { uchar *m; ushort *r, *w, *ew; USED(i); USED(o); m = bmask.grey; w = (ushort*)bdst.red; r = (ushort*)bsrc.red; ew = w+dx; for(; w < ew; w++,r++) if(*m++) *w = *r; return bdst; /* not used */ } static Buffer boolcopy24(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o) { uchar *m; uchar *r, *w, *ew; USED(i); USED(o); m = bmask.grey; w = bdst.red; r = bsrc.red; ew = w+dx*3; while(w < ew){ if(*m++){ *w++ = *r++; *w++ = *r++; *w++ = *r++; }else{ w += 3; r += 3; } } return bdst; /* not used */ } static Buffer boolcopy32(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o) { uchar *m; ulong *r, *w, *ew; USED(i); USED(o); m = bmask.grey; w = (ulong*)bdst.red; r = (ulong*)bsrc.red; ew = w+dx; for(; w < ew; w++,r++) if(*m++) *w = *r; return bdst; /* not used */ } static Buffer genconv(Param *p, uchar *buf, int y) { Buffer b; int nb; uchar *r, *w, *ew; /* read from source into RGB format in convbuf */ b = p->convreadcall(p, p->convbuf, y); /* write RGB format into dst format in buf */ p->convwritecall(p->convdpar, buf, b); if(p->convdx){ nb = p->convdpar->img->depth/8; r = buf; w = buf+nb*p->dx; ew = buf+nb*p->convdx; while(wchan == src->chan && !(src->flags&Frepl)){ //if(drawdebug) iprint("readptr..."); return readptr; } if(dst->chan==CMAP8 && (src->chan==GREY1||src->chan==GREY2||src->chan==GREY4)){ /* cheat because we know the replicated value is exactly the color map entry. */ //if(drawdebug) iprint("Readnbit..."); return readnbit; } spar->convreadcall = readfn(src); spar->convwritecall = writefn(dst); spar->convdpar = dpar; /* allocate a conversion buffer */ spar->convbufoff = ndrawbuf; ndrawbuf += spar->dx*4; if(spar->dx > Dx(spar->img->r)){ spar->convdx = spar->dx; spar->dx = Dx(spar->img->r); } //if(drawdebug) iprint("genconv..."); return genconv; } ulong _pixelbits(Memimage *i, Point pt) { uchar *p; ulong val; int off, bpp, npack; val = 0; p = byteaddr(i, pt); switch(bpp=i->depth){ case 1: case 2: case 4: npack = 8/bpp; off = pt.x%npack; val = p[0] >> bpp*(npack-1-off); val &= (1<flags&Frepl && Dx(mask->r)==1 && Dy(mask->r)==1 && pixelbits(mask, mask->r.min)==~0) return boolmemmove; switch(img->depth){ case 8: return boolcopy8; case 16: return boolcopy16; case 24: return boolcopy24; case 32: return boolcopy32; default: assert(0 /* boolcopyfn */); } return nil; } /* * Optimized draw for filling and scrolling; uses memset and memmove. * static void memsetb(void *vp, uchar val, int n) { uchar *p, *ep; p = vp; ep = p+n; while(p>8; c = val>>16; while(pchan; chan; chan>>=8){ nb = NBITS(chan); ov = v = val&((1<>= nb; while(nb < 8){ v |= v<>= (nb-8); switch(TYPE(chan)){ case CRed: r = v; break; case CGreen: g = v; break; case CBlue: b = v; break; case CAlpha: a = v; break; case CGrey: r = g = b = v; break; case CMap: p = img->cmap->cmap2rgb+3*ov; r = *p++; g = *p++; b = *p; break; } } return (r<<24)|(g<<16)|(b<<8)|a; } ulong _rgbatoimg(Memimage *img, ulong rgba) { ulong chan; int d, nb; ulong v; uchar *p, r, g, b, a, m; v = 0; r = rgba>>24; g = rgba>>16; b = rgba>>8; a = rgba; d = 0; for(chan=img->chan; chan; chan>>=8){ nb = NBITS(chan); switch(TYPE(chan)){ case CRed: v |= (r>>(8-nb))<>(8-nb))<>(8-nb))<>(8-nb))<cmap->rgb2cmap; m = p[(r>>4)*256+(g>>4)*16+(b>>4)]; v |= (m>>(8-nb))<>(8-nb))<r); dy = Dy(par->r); src = par->src; dst = par->dst; op = par->op; DBG print("state %lux mval %lux dd %d\n", par->state, par->mval, dst->depth); /* * If we have an opaque mask and source is one opaque pixel we can convert to the * destination format and just replicate with memset. */ m = Simplesrc|Simplemask|Fullmask; if((par->state&m)==m && (par->srgba&0xFF) == 0xFF && (op ==S || op == SoverD)){ uchar *dp, p[4]; int d, dwid, ppb, np, nb; uchar lm, rm; DBG print("memopt, dst %p, dst->data->bdata %p\n", dst, dst->data->bdata); dwid = dst->width*sizeof(ulong); dp = byteaddr(dst, par->r.min); v = par->sdval; DBG print("sdval %lud, depth %d\n", v, dst->depth); switch(dst->depth){ case 1: case 2: case 4: for(d=dst->depth; d<8; d*=2) v |= (v<depth; /* pixels per byte */ m = ppb-1; /* left edge */ np = par->r.min.x&m; /* no. pixels unused on left side of word */ dx -= (ppb-np); nb = 8 - np * dst->depth; /* no. bits used on right side of word */ lm = (1<r.min.x, nb, lm, ppb, m); /* right edge */ np = par->r.max.x&m; /* no. pixels used on left side of word */ dx -= np; nb = 8 - np * dst->depth; /* no. bits unused on right side of word */ rm = ~((1<r.max.x, nb, rm, ppb, m); DBG print("dx %d Dx %d\n", dx, Dx(par->r)); /* lm, rm are masks that are 1 where we should touch the bits */ if(dx < 0){ /* just one byte */ lm &= rm; for(y=0; y>8; v = *(ushort*)(void*)p; DBG print("dp=%p; dx=%d; for(y=0; y<%d; y++, dp+=%d)\nmemsets(dp, v, dx);\n", dp, dx, dy, dwid); for(y=0; y>8; p[2] = v>>16; p[3] = v>>24; v = *(ulong*)(void*)p; for(y=0; ystate&(m|Replsrc))==m && src->depth >= 8 && src->chan == dst->chan && !(src->flags&Falpha) && (op == S || op == SoverD)){ uchar *sp, *dp; long swid, dwid, nb; int dir; if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)) dir = -1; else dir = 1; swid = src->width*sizeof(ulong); dwid = dst->width*sizeof(ulong); sp = byteaddr(src, par->sr.min); dp = byteaddr(dst, par->r.min); if(dir == -1){ sp += (dy-1)*swid; dp += (dy-1)*dwid; swid = -swid; dwid = -dwid; } nb = (dx*src->depth)/8; for(y=0; ystate&(Simplemask|Simplesrc|Replmask|Replsrc))==0 && dst->chan==GREY1 && src->chan==GREY1 && par->mask->chan==GREY1 && (par->r.min.x&7)==(par->sr.min.x&7) && (par->r.min.x&7)==(par->mr.min.x&7)){ uchar *sp, *dp, *mp; uchar lm, rm; long swid, dwid, mwid; int i, x, dir; sp = byteaddr(src, par->sr.min); dp = byteaddr(dst, par->r.min); mp = byteaddr(par->mask, par->mr.min); swid = src->width*sizeof(ulong); dwid = dst->width*sizeof(ulong); mwid = par->mask->width*sizeof(ulong); if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)){ dir = -1; }else dir = 1; lm = 0xFF>>(par->r.min.x&7); rm = 0xFF<<(8-(par->r.max.x&7)); dx -= (8-(par->r.min.x&7)) + (par->r.max.x&7); if(dx < 0){ /* one byte wide */ lm &= rm; if(dir == -1){ dp += dwid*(dy-1); sp += swid*(dy-1); mp += mwid*(dy-1); dwid = -dwid; swid = -swid; mwid = -mwid; } for(y=0; ymask->flags, par->mask->depth, par->src->flags, Dx(par->src->r), Dy(par->src->r), par->dst->depth, par->dst->data, par->src->data); mask = par->mask; src = par->src; dst = par->dst; r = par->r; mr = par->mr; op = par->op; if((par->state&(Replsrc|Simplesrc|Replmask)) != (Replsrc|Simplesrc) || mask->depth != 1 || src->flags&Falpha || dst->depth<8 || dst->data==src->data || op != SoverD) return 0; //if(drawdebug) iprint("chardraw..."); depth = mask->depth; maskwid = mask->width*sizeof(ulong); rp = byteaddr(mask, mr.min); npack = 8/depth; bsh = (mr.min.x % npack) * depth; wp = byteaddr(dst, r.min); dstwid = dst->width*sizeof(ulong); DBG print("bsh %d\n", bsh); dy = Dy(r); dx = Dx(r); ddepth = dst->depth; /* * for loop counts from bsh to bsh+dx * * we want the bottom bits to be the amount * to shift the pixels down, so for n≡0 (mod 8) we want * bottom bits 7. for n≡1, 6, etc. * the bits come from -n-1. */ bx = -bsh-1; ex = -bsh-1-dx; SET(bits); v = par->sdval; /* make little endian */ sp[0] = v; sp[1] = v>>8; sp[2] = v>>16; sp[3] = v>>24; //print("sp %x %x %x %x\n", sp[0], sp[1], sp[2], sp[3]); for(y=0; yex; x--, wc++){ i = x&7; if(i == 8-1) bits = *q++; DBG print("bits %lux sh %d...", bits, i); if((bits>>i)&1) *wc = v; } break; case 16: ws = (ushort*)wp; v = *(ushort*)(void*)sp; for(x=bx; x>ex; x--, ws++){ i = x&7; if(i == 8-1) bits = *q++; DBG print("bits %lux sh %d...", bits, i); if((bits>>i)&1) *ws = v; } break; case 24: wc = wp; for(x=bx; x>ex; x--, wc+=3){ i = x&7; if(i == 8-1) bits = *q++; DBG print("bits %lux sh %d...", bits, i); if((bits>>i)&1){ wc[0] = sp[0]; wc[1] = sp[1]; wc[2] = sp[2]; } } break; case 32: wl = (ulong*)wp; v = *(ulong*)(void*)sp; for(x=bx; x>ex; x--, wl++){ i = x&7; if(i == 8-1) bits = *q++; DBG iprint("bits %lux sh %d...", bits, i); if((bits>>i)&1) *wl = v; } break; } } DBG print("\n"); return 1; } #undef DBG /* * Fill entire byte with replicated (if necessary) copy of source pixel, * assuming destination ldepth is >= source ldepth. * * This code is just plain wrong for >8bpp. * ulong membyteval(Memimage *src) { int i, val, bpp; uchar uc; unloadmemimage(src, src->r, &uc, 1); bpp = src->depth; uc <<= (src->r.min.x&(7/src->depth))*src->depth; uc &= ~(0xFF>>bpp); // pixel value is now in high part of byte. repeat throughout byte val = uc; for(i=bpp; i<8; i<<=1) val |= val>>i; return val; } * */ void _memfillcolor(Memimage *i, ulong val) { ulong bits; int d, y; if(val == DNofill) return; bits = _rgbatoimg(i, val); switch(i->depth){ case 24: /* 24-bit images suck */ for(y=i->r.min.y; yr.max.y; y++) memset24(byteaddr(i, Pt(i->r.min.x, y)), bits, Dx(i->r)); break; default: /* 1, 2, 4, 8, 16, 32 */ for(d=i->depth; d<32; d*=2) bits = (bits << d) | bits; memsetl(wordaddr(i, i->r.min), bits, i->width*Dy(i->r)); break; } } drawterm-20170818/libmemdraw/drawtest.c000066400000000000000000000556211314554504700177600ustar00rootroot00000000000000#include #include #include #include #include #define DBG if(0) #define RGB2K(r,g,b) ((299*((ulong)(r))+587*((ulong)(g))+114*((ulong)(b)))/1000) /* * This program tests the 'memimagedraw' primitive stochastically. * It tests the combination aspects of it thoroughly, but since the * three images it uses are disjoint, it makes no check of the * correct behavior when images overlap. That is, however, much * easier to get right and to test. */ void drawonepixel(Memimage*, Point, Memimage*, Point, Memimage*, Point); void verifyone(void); void verifyline(void); void verifyrect(void); void verifyrectrepl(int, int); void putpixel(Memimage *img, Point pt, ulong nv); ulong rgbatopix(uchar, uchar, uchar, uchar); char *dchan, *schan, *mchan; int dbpp, sbpp, mbpp; int drawdebug=0; int seed; int niters = 100; int dbpp; /* bits per pixel in destination */ int sbpp; /* bits per pixel in src */ int mbpp; /* bits per pixel in mask */ int dpm; /* pixel mask at high part of byte, in destination */ int nbytes; /* in destination */ int Xrange = 64; int Yrange = 8; Memimage *dst; Memimage *src; Memimage *mask; Memimage *stmp; Memimage *mtmp; Memimage *ones; uchar *dstbits; uchar *srcbits; uchar *maskbits; ulong *savedstbits; void rdb(void) { } int iprint(char *fmt, ...) { int n; va_list va; char buf[1024]; va_start(va, fmt); n = doprint(buf, buf+sizeof buf, fmt, va) - buf; va_end(va); write(1,buf,n); return 1; } void main(int argc, char *argv[]) { memimageinit(); seed = time(0); ARGBEGIN{ case 'x': Xrange = atoi(ARGF()); break; case 'y': Yrange = atoi(ARGF()); break; case 'n': niters = atoi(ARGF()); break; case 's': seed = atoi(ARGF()); break; }ARGEND dchan = "r8g8b8"; schan = "r8g8b8"; mchan = "r8g8b8"; switch(argc){ case 3: mchan = argv[2]; case 2: schan = argv[1]; case 1: dchan = argv[0]; case 0: break; default: goto Usage; Usage: fprint(2, "usage: dtest [dchan [schan [mchan]]]\n"); exits("usage"); } fmtinstall('b', numbconv); /* binary! */ fprint(2, "%s -x %d -y %d -s 0x%x %s %s %s\n", argv0, Xrange, Yrange, seed, dchan, schan, mchan); srand(seed); dst = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(dchan)); src = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan)); mask = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan)); stmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan)); mtmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan)); ones = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan)); // print("chan %lux %lux %lux %lux %lux %lux\n", dst->chan, src->chan, mask->chan, stmp->chan, mtmp->chan, ones->chan); if(dst==0 || src==0 || mask==0 || mtmp==0 || ones==0) { Alloc: fprint(2, "dtest: allocation failed: %r\n"); exits("alloc"); } nbytes = (4*Xrange+4)*Yrange; srcbits = malloc(nbytes); dstbits = malloc(nbytes); maskbits = malloc(nbytes); savedstbits = malloc(nbytes); if(dstbits==0 || srcbits==0 || maskbits==0 || savedstbits==0) goto Alloc; dbpp = dst->depth; sbpp = src->depth; mbpp = mask->depth; dpm = 0xFF ^ (0xFF>>dbpp); memset(ones->data->bdata, 0xFF, ones->width*sizeof(ulong)*Yrange); fprint(2, "dtest: verify single pixel operation\n"); verifyone(); fprint(2, "dtest: verify full line non-replicated\n"); verifyline(); fprint(2, "dtest: verify full rectangle non-replicated\n"); verifyrect(); fprint(2, "dtest: verify full rectangle source replicated\n"); verifyrectrepl(1, 0); fprint(2, "dtest: verify full rectangle mask replicated\n"); verifyrectrepl(0, 1); fprint(2, "dtest: verify full rectangle source and mask replicated\n"); verifyrectrepl(1, 1); exits(0); } /* * Dump out an ASCII representation of an image. The label specifies * a list of characters to put at various points in the picture. */ static void Bprintr5g6b5(Biobuf *bio, char*, ulong v) { int r,g,b; r = (v>>11)&31; g = (v>>5)&63; b = v&31; Bprint(bio, "%.2x%.2x%.2x", r,g,b); } static void Bprintr5g5b5a1(Biobuf *bio, char*, ulong v) { int r,g,b,a; r = (v>>11)&31; g = (v>>6)&31; b = (v>>1)&31; a = v&1; Bprint(bio, "%.2x%.2x%.2x%.2x", r,g,b,a); } void dumpimage(char *name, Memimage *img, void *vdata, Point labelpt) { Biobuf b; uchar *data; uchar *p; char *arg; void (*fmt)(Biobuf*, char*, ulong); int npr, x, y, nb, bpp; ulong v, mask; Rectangle r; fmt = nil; arg = nil; switch(img->depth){ case 1: case 2: case 4: fmt = (void(*)(Biobuf*,char*,ulong))Bprint; arg = "%.1ux"; break; case 8: fmt = (void(*)(Biobuf*,char*,ulong))Bprint; arg = "%.2ux"; break; case 16: arg = nil; if(img->chan == RGB16) fmt = Bprintr5g6b5; else{ fmt = (void(*)(Biobuf*,char*,ulong))Bprint; arg = "%.4ux"; } break; case 24: fmt = (void(*)(Biobuf*,char*,ulong))Bprint; arg = "%.6lux"; break; case 32: fmt = (void(*)(Biobuf*,char*,ulong))Bprint; arg = "%.8lux"; break; } if(fmt == nil){ fprint(2, "bad format\n"); abort(); } r = img->r; Binit(&b, 2, OWRITE); data = vdata; bpp = img->depth; Bprint(&b, "%s\t%d\tr %R clipr %R repl %d data %p *%P\n", name, r.min.x, r, img->clipr, (img->flags&Frepl) ? 1 : 0, vdata, labelpt); mask = (1ULL<data->bdata); Bprint(&b, "%-4d\t", y); // for(x=r.min.x; x>nb)&mask); } Bprint(&b, "\n"); } Bterm(&b); } /* * Verify that the destination pixel has the specified value. * The value is in the high bits of v, suitably masked, but must * be extracted from the destination Memimage. */ void checkone(Point p, Point sp, Point mp) { int delta; uchar *dp, *sdp; delta = (uchar*)byteaddr(dst, p)-(uchar*)dst->data->bdata; dp = (uchar*)dst->data->bdata+delta; sdp = (uchar*)savedstbits+delta; if(memcmp(dp, sdp, (dst->depth+7)/8) != 0) { fprint(2, "dtest: one bad pixel drawing at dst %P from source %P mask %P\n", p, sp, mp); fprint(2, " %.2ux %.2ux %.2ux %.2ux should be %.2ux %.2ux %.2ux %.2ux\n", dp[0], dp[1], dp[2], dp[3], sdp[0], sdp[1], sdp[2], sdp[3]); fprint(2, "addresses dst %p src %p mask %p\n", dp, byteaddr(src, sp), byteaddr(mask, mp)); dumpimage("src", src, src->data->bdata, sp); dumpimage("mask", mask, mask->data->bdata, mp); dumpimage("origdst", dst, dstbits, p); dumpimage("dst", dst, dst->data->bdata, p); dumpimage("gooddst", dst, savedstbits, p); abort(); } } /* * Verify that the destination line has the same value as the saved line. */ #define RECTPTS(r) (r).min.x, (r).min.y, (r).max.x, (r).max.y void checkline(Rectangle r, Point sp, Point mp, int y, Memimage *stmp, Memimage *mtmp) { ulong *dp; int nb; ulong *saved; dp = wordaddr(dst, Pt(0, y)); saved = savedstbits + y*dst->width; if(dst->depth < 8) nb = Xrange/(8/dst->depth); else nb = Xrange*(dst->depth/8); if(memcmp(dp, saved, nb) != 0){ fprint(2, "dtest: bad line at y=%d; saved %p dp %p\n", y, saved, dp); fprint(2, "draw dst %R src %P mask %P\n", r, sp, mp); dumpimage("src", src, src->data->bdata, sp); if(stmp) dumpimage("stmp", stmp, stmp->data->bdata, sp); dumpimage("mask", mask, mask->data->bdata, mp); if(mtmp) dumpimage("mtmp", mtmp, mtmp->data->bdata, mp); dumpimage("origdst", dst, dstbits, r.min); dumpimage("dst", dst, dst->data->bdata, r.min); dumpimage("gooddst", dst, savedstbits, r.min); abort(); } } /* * Fill the bits of an image with random data. * The Memimage parameter is used only to make sure * the data is well formatted: only ucbits is written. */ void fill(Memimage *img, uchar *ucbits) { int i, x, y; ushort *up; uchar alpha, r, g, b; void *data; if((img->flags&Falpha) == 0){ up = (ushort*)ucbits; for(i=0; i> 7; if(i+i != nbytes) *(uchar*)up = lrand() >> 7; }else{ data = img->data->bdata; img->data->bdata = ucbits; for(x=img->r.min.x; xr.max.x; x++) for(y=img->r.min.y; yr.max.y; y++){ alpha = rand() >> 4; r = rand()%(alpha+1); g = rand()%(alpha+1); b = rand()%(alpha+1); putpixel(img, Pt(x,y), rgbatopix(r,g,b,alpha)); } img->data->bdata = data; } } /* * Mask is preset; do the rest */ void verifyonemask(void) { Point dp, sp, mp; fill(dst, dstbits); fill(src, srcbits); memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange); memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); dp.x = nrand(Xrange); dp.y = nrand(Yrange); sp.x = nrand(Xrange); sp.y = nrand(Yrange); mp.x = nrand(Xrange); mp.y = nrand(Yrange); drawonepixel(dst, dp, src, sp, mask, mp); memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange); memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); memimagedraw(dst, Rect(dp.x, dp.y, dp.x+1, dp.y+1), src, sp, mask, mp, SoverD); memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); checkone(dp, sp, mp); } void verifyone(void) { int i; /* mask all zeros */ memset(maskbits, 0, nbytes); for(i=0; idata->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange); memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); dr.min.x = nrand(Xrange-1); dr.min.y = nrand(Yrange-1); dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x); dr.max.y = dr.min.y + 1; sp.x = nrand(Xrange); sp.y = nrand(Yrange); mp.x = nrand(Xrange); mp.y = nrand(Yrange); tp = sp; up = mp; for(x=dr.min.x; xdata->bdata, dst->width*sizeof(ulong)*Yrange); memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); memimagedraw(dst, dr, src, sp, mask, mp, SoverD); checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), dr.min.y, nil, nil); } void verifyline(void) { int i; /* mask all ones */ memset(maskbits, 0xFF, nbytes); for(i=0; idata->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange); memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); dr.min.x = nrand(Xrange-1); dr.min.y = nrand(Yrange-1); dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x); dr.max.y = dr.min.y + 1 + nrand(Yrange-1-dr.min.y); sp.x = nrand(Xrange); sp.y = nrand(Yrange); mp.x = nrand(Xrange); mp.y = nrand(Yrange); tp = sp; up = mp; for(y=dr.min.y; ydata->bdata, dst->width*sizeof(ulong)*Yrange); memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); memimagedraw(dst, dr, src, sp, mask, mp, SoverD); for(y=0; yr, sp), drawrepl(mask->r, mp), y, nil, nil); } void verifyrect(void) { int i; /* mask all zeros */ memset(maskbits, 0, nbytes); for(i=0; ir) */ r.min.x = nrand(Xrange-1); r.min.y = nrand(Yrange-1); /* make it trivial more often than pure chance allows */ switch(lrand()&0){ case 1: r.max.x = r.min.x + 2; r.max.y = r.min.y + 2; if(r.max.x < Xrange && r.max.y < Yrange) break; /* fall through */ case 0: r.max.x = r.min.x + 1; r.max.y = r.min.y + 1; break; default: if(r.min.x+3 >= Xrange) r.max.x = Xrange; else r.max.x = r.min.x+3 + nrand(Xrange-(r.min.x+3)); if(r.min.y+3 >= Yrange) r.max.y = Yrange; else r.max.y = r.min.y+3 + nrand(Yrange-(r.min.y+3)); } assert(r.min.x >= 0); assert(r.max.x <= Xrange); assert(r.min.y >= 0); assert(r.max.y <= Yrange); /* copy from i to tmp so we have just the replicated bits */ nb = tmp->width*sizeof(ulong)*Yrange; memset(tmp->data->bdata, 0, nb); memimagedraw(tmp, r, i, r.min, ones, r.min, SoverD); memmove(i->data->bdata, tmp->data->bdata, nb); /* i is now a non-replicated instance of the replication */ /* replicate it by hand through tmp */ memset(tmp->data->bdata, 0, nb); x = -(tilexy(r.min.x, r.max.x, 0)-r.min.x); for(; xflags |= Frepl; i->r = r; i->clipr = randrect(); // fprint(2, "replicate [[%d %d] [%d %d]] [[%d %d][%d %d]]\n", r.min.x, r.min.y, r.max.x, r.max.y, // i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y); tmp->clipr = i->clipr; } /* * Mask is preset; do the rest */ void verifyrectmaskrepl(int srcrepl, int maskrepl) { Point sp, mp, tp, up; Rectangle dr; int x, y; Memimage *s, *m; // print("verfrect %d %d\n", srcrepl, maskrepl); src->flags &= ~Frepl; src->r = Rect(0, 0, Xrange, Yrange); src->clipr = src->r; stmp->flags &= ~Frepl; stmp->r = Rect(0, 0, Xrange, Yrange); stmp->clipr = src->r; mask->flags &= ~Frepl; mask->r = Rect(0, 0, Xrange, Yrange); mask->clipr = mask->r; mtmp->flags &= ~Frepl; mtmp->r = Rect(0, 0, Xrange, Yrange); mtmp->clipr = mask->r; fill(dst, dstbits); fill(src, srcbits); memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange); memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); if(srcrepl){ replicate(src, stmp); s = stmp; }else s = src; if(maskrepl){ replicate(mask, mtmp); m = mtmp; }else m = mask; dr = randrect(); sp.x = nrand(Xrange); sp.y = nrand(Yrange); mp.x = nrand(Xrange); mp.y = nrand(Yrange); DBG print("smalldraws\n"); for(tp.y=sp.y,up.y=mp.y,y=dr.min.y; ydata->bdata, dst->width*sizeof(ulong)*Yrange); memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); DBG print("bigdraw\n"); memimagedraw(dst, dr, src, sp, mask, mp, SoverD); for(y=0; yr, sp), drawrepl(mask->r, mp), y, srcrepl?stmp:nil, maskrepl?mtmp:nil); } void verifyrectrepl(int srcrepl, int maskrepl) { int i; /* mask all ones */ memset(maskbits, 0xFF, nbytes); for(i=0; i>= (nhave-nwant); return v & ((1<>24; *r = v>>16; *g = v>>8; *b = v; } /* * Convert uchar channels into ulong pixel. */ ulong rgbatopix(uchar r, uchar g, uchar b, uchar a) { return (a<<24)|(r<<16)|(g<<8)|b; } /* * Retrieve the pixel value at pt in the image. */ ulong getpixel(Memimage *img, Point pt) { uchar r, g, b, a, *p; int nbits, npack, bpp; ulong v, c, rbits, bits; r = g = b = 0; a = ~0; /* default alpha is full */ p = byteaddr(img, pt); v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24); bpp = img->depth; if(bpp<8){ /* * Sub-byte greyscale pixels. * * We want to throw away the top pt.x%npack pixels and then use the next bpp bits * in the bottom byte of v. This madness is due to having big endian bits * but little endian bytes. */ npack = 8/bpp; v >>= 8 - bpp*(pt.x%npack+1); v &= (1<chan; c; c>>=8){ nbits = NBITS(c); bits = v & ((1<>= nbits; switch(TYPE(c)){ case CRed: r = rbits; break; case CGreen: g = rbits; break; case CBlue: b = rbits; break; case CGrey: r = g = b = rbits; break; case CAlpha: a = rbits; break; case CMap: p = img->cmap->cmap2rgb + 3*bits; r = p[0]; g = p[1]; b = p[2]; break; case CIgnore: break; default: fprint(2, "unknown channel type %lud\n", TYPE(c)); abort(); } } } return rgbatopix(r, g, b, a); } /* * Return the greyscale equivalent of a pixel. */ uchar getgrey(Memimage *img, Point pt) { uchar r, g, b, a; pixtorgba(getpixel(img, pt), &r, &g, &b, &a); return RGB2K(r, g, b); } /* * Return the value at pt in image, if image is interpreted * as a mask. This means the alpha channel if present, else * the greyscale or its computed equivalent. */ uchar getmask(Memimage *img, Point pt) { if(img->flags&Falpha) return getpixel(img, pt)>>24; else return getgrey(img, pt); } #undef DBG #define DBG if(0) /* * Write a pixel to img at point pt. * * We do this by reading a 32-bit little endian * value from p and then writing it back * after tweaking the appropriate bits. Because * the data is little endian, we don't have to worry * about what the actual depth is, as long as it is * less than 32 bits. */ void putpixel(Memimage *img, Point pt, ulong nv) { uchar r, g, b, a, *p, *q; ulong c, mask, bits, v; int bpp, sh, npack, nbits; pixtorgba(nv, &r, &g, &b, &a); p = byteaddr(img, pt); v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24); bpp = img->depth; DBG print("v %.8lux...", v); if(bpp < 8){ /* * Sub-byte greyscale pixels. We need to skip the leftmost pt.x%npack pixels, * which is equivalent to skipping the rightmost npack - pt.x%npack - 1 pixels. */ npack = 8/bpp; sh = bpp*(npack - pt.x%npack - 1); bits = RGB2K(r,g,b); DBG print("repl %lux 8 %d = %lux...", bits, bpp, replbits(bits, 8, bpp)); bits = replbits(bits, 8, bpp); mask = (1<chan; c; c>>=8){ nbits = NBITS(c); switch(TYPE(c)){ case CRed: bits = r; break; case CGreen: bits = g; break; case CBlue: bits = b; break; case CGrey: bits = RGB2K(r, g, b); break; case CAlpha: bits = a; break; case CIgnore: bits = 0; break; case CMap: q = img->cmap->rgb2cmap; bits = q[(r>>4)*16*16+(g>>4)*16+(b>>4)]; break; default: SET(bits); fprint(2, "unknown channel type %lud\n", TYPE(c)); abort(); } DBG print("repl %lux 8 %d = %lux...", bits, nbits, replbits(bits, 8, nbits)); if(TYPE(c) != CMap) bits = replbits(bits, 8, nbits); mask = (1<>8; p[2] = v>>16; p[3] = v>>24; } #undef DBG #define DBG if(0) void drawonepixel(Memimage *dst, Point dp, Memimage *src, Point sp, Memimage *mask, Point mp) { uchar m, M, sr, sg, sb, sa, sk, dr, dg, db, da, dk; pixtorgba(getpixel(dst, dp), &dr, &dg, &db, &da); pixtorgba(getpixel(src, sp), &sr, &sg, &sb, &sa); m = getmask(mask, mp); M = 255-(sa*m)/255; DBG print("dst %x %x %x %x src %x %x %x %x m %x = ", dr,dg,db,da, sr,sg,sb,sa, m); if(dst->flags&Fgrey){ /* * We need to do the conversion to grey before the alpha calculation * because the draw operator does this, and we need to be operating * at the same precision so we get exactly the same answers. */ sk = RGB2K(sr, sg, sb); dk = RGB2K(dr, dg, db); dk = (sk*m + dk*M)/255; dr = dg = db = dk; da = (sa*m + da*M)/255; }else{ /* * True color alpha calculation treats all channels (including alpha) * the same. It might have been nice to use an array, but oh well. */ dr = (sr*m + dr*M)/255; dg = (sg*m + dg*M)/255; db = (sb*m + db*M)/255; da = (sa*m + da*M)/255; } DBG print("%x %x %x %x\n", dr,dg,db,da); putpixel(dst, dp, rgbatopix(dr, dg, db, da)); } drawterm-20170818/libmemdraw/ellipse.c000066400000000000000000000114001314554504700175430ustar00rootroot00000000000000#include #include #include #include #include /* * ellipse(dst, c, a, b, t, src, sp) * draws an ellipse centered at c with semiaxes a,b>=0 * and semithickness t>=0, or filled if t<0. point sp * in src maps to c in dst * * very thick skinny ellipses are brushed with circles (slow) * others are approximated by filling between 2 ellipses * criterion for very thick when b 0.5*x/(1-x) * where x = b/a */ typedef struct Param Param; typedef struct State State; static void bellipse(int, State*, Param*); static void erect(int, int, int, int, Param*); static void eline(int, int, int, int, Param*); struct Param { Memimage *dst; Memimage *src; Point c; int t; Point sp; Memimage *disc; int op; }; /* * denote residual error by e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 * e(x,y) = 0 on ellipse, e(x,y) < 0 inside, e(x,y) > 0 outside */ struct State { int a; int x; vlong a2; /* a^2 */ vlong b2; /* b^2 */ vlong b2x; /* b^2 * x */ vlong a2y; /* a^2 * y */ vlong c1; vlong c2; /* test criteria */ vlong ee; /* ee = e(x+1/2,y-1/2) - (a^2+b^2)/4 */ vlong dxe; vlong dye; vlong d2xe; vlong d2ye; }; static State* newstate(State *s, int a, int b) { s->x = 0; s->a = a; s->a2 = (vlong)(a*a); s->b2 = (vlong)(b*b); s->b2x = (vlong)0; s->a2y = s->a2*(vlong)b; s->c1 = -((s->a2>>2) + (vlong)(a&1) + s->b2); s->c2 = -((s->b2>>2) + (vlong)(b&1)); s->ee = -s->a2y; s->dxe = (vlong)0; s->dye = s->ee<<1; s->d2xe = s->b2<<1; s->d2ye = s->a2<<1; return s; } /* * return x coord of rightmost pixel on next scan line */ static int step(State *s) { while(s->x < s->a) { if(s->ee+s->b2x <= s->c1 || /* e(x+1,y-1/2) <= 0 */ s->ee+s->a2y <= s->c2) { /* e(x+1/2,y) <= 0 (rare) */ s->dxe += s->d2xe; s->ee += s->dxe; s->b2x += s->b2; s->x++; continue; } s->dye += s->d2ye; s->ee += s->dye; s->a2y -= s->a2; if(s->ee-s->a2y <= s->c2) { /* e(x+1/2,y-1) <= 0 */ s->dxe += s->d2xe; s->ee += s->dxe; s->b2x += s->b2; return s->x++; } break; } return s->x; } void memellipse(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int op) { State in, out; int y, inb, inx, outx, u; Param p; if(a < 0) a = -a; if(b < 0) b = -b; p.dst = dst; p.src = src; p.c = c; p.t = t; p.sp = subpt(sp, c); p.disc = nil; p.op = op; u = (t<<1)*(a-b); if((bb*b) || (aa*a)) { /* if(bb*b/a || aa*a/b) # very thick */ bellipse(b, newstate(&in, a, b), &p); return; } if(t < 0) { inb = -1; newstate(&out, a, y = b); } else { inb = b - t; newstate(&out, a+t, y = b+t); } if(t > 0) newstate(&in, a-t, inb); inx = 0; for( ; y>=0; y--) { outx = step(&out); if(y > inb) { erect(-outx, y, outx, y, &p); if(y != 0) erect(-outx, -y, outx, -y, &p); continue; } if(t > 0) { inx = step(&in); if(y == inb) inx = 0; } else if(inx > outx) inx = outx; erect(inx, y, outx, y, &p); if(y != 0) erect(inx, -y, outx, -y, &p); erect(-outx, y, -inx, y, &p); if(y != 0) erect(-outx, -y, -inx, -y, &p); inx = outx + 1; } } static Point p00 = {0, 0}; /* * a brushed ellipse */ static void bellipse(int y, State *s, Param *p) { int t, ox, oy, x, nx; t = p->t; p->disc = allocmemimage(Rect(-t,-t,t+1,t+1), GREY1); if(p->disc == nil) return; memfillcolor(p->disc, DTransparent); memellipse(p->disc, p00, t, t, -1, memopaque, p00, p->op); oy = y; ox = 0; nx = x = step(s); do { while(nx==x && y-->0) nx = step(s); y++; eline(-x,-oy,-ox, -y, p); eline(ox,-oy, x, -y, p); eline(-x, y,-ox, oy, p); eline(ox, y, x, oy, p); ox = x+1; x = nx; y--; oy = y; } while(oy > 0); } /* * a rectangle with closed (not half-open) coordinates expressed * relative to the center of the ellipse */ static void erect(int x0, int y0, int x1, int y1, Param *p) { Rectangle r; /* print("R %d,%d %d,%d\n", x0, y0, x1, y1); */ r = Rect(p->c.x+x0, p->c.y+y0, p->c.x+x1+1, p->c.y+y1+1); memdraw(p->dst, r, p->src, addpt(p->sp, r.min), memopaque, p00, p->op); } /* * a brushed point similarly specified */ static void epoint(int x, int y, Param *p) { Point p0; Rectangle r; /* print("P%d %d,%d\n", p->t, x, y); */ p0 = Pt(p->c.x+x, p->c.y+y); r = Rpt(addpt(p0, p->disc->r.min), addpt(p0, p->disc->r.max)); memdraw(p->dst, r, p->src, addpt(p->sp, r.min), p->disc, p->disc->r.min, p->op); } /* * a brushed horizontal or vertical line similarly specified */ static void eline(int x0, int y0, int x1, int y1, Param *p) { /* print("L%d %d,%d %d,%d\n", p->t, x0, y0, x1, y1); */ if(x1 > x0+1) erect(x0+1, y0-p->t, x1-1, y1+p->t, p); else if(y1 > y0+1) erect(x0-p->t, y0+1, x1+p->t, y1-1, p); epoint(x0, y0, p); if(x1-x0 || y1-y0) epoint(x1, y1, p); } drawterm-20170818/libmemdraw/fillpoly.c000066400000000000000000000233651314554504700177550ustar00rootroot00000000000000#include #include #include #include #include typedef struct Seg Seg; struct Seg { Point p0; Point p1; long num; long den; long dz; long dzrem; long z; long zerr; long d; }; static void zsort(Seg **seg, Seg **ep); static int ycompare(const void*, const void*); static int xcompare(const void*, const void*); static int zcompare(const void*, const void*); static void xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int, int, int); static void yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int); #ifdef NOT static void fillcolor(Memimage *dst, int left, int right, int y, Memimage *src, Point p) { int srcval; USED(src); srcval = p.x; p.x = left; p.y = y; memset(byteaddr(dst, p), srcval, right-left); } #endif static void fillline(Memimage *dst, int left, int right, int y, Memimage *src, Point p, int op) { Rectangle r; r.min.x = left; r.min.y = y; r.max.x = right; r.max.y = y+1; p.x += left; p.y += y; memdraw(dst, r, src, p, memopaque, p, op); } static void fillpoint(Memimage *dst, int x, int y, Memimage *src, Point p, int op) { Rectangle r; r.min.x = x; r.min.y = y; r.max.x = x+1; r.max.y = y+1; p.x += x; p.y += y; memdraw(dst, r, src, p, memopaque, p, op); } void memfillpoly(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int op) { _memfillpolysc(dst, vert, nvert, w, src, sp, 0, 0, 0, op); } void _memfillpolysc(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op) { Seg **seg, *segtab; Point p0; int i; if(nvert == 0) return; seg = malloc((nvert+2)*sizeof(Seg*)); if(seg == nil) return; segtab = malloc((nvert+1)*sizeof(Seg)); if(segtab == nil) { free(seg); return; } sp.x = (sp.x - vert[0].x) >> fixshift; sp.y = (sp.y - vert[0].y) >> fixshift; p0 = vert[nvert-1]; if(!fixshift) { p0.x <<= 1; p0.y <<= 1; } for(i = 0; i < nvert; i++) { segtab[i].p0 = p0; p0 = vert[i]; if(!fixshift) { p0.x <<= 1; p0.y <<= 1; } segtab[i].p1 = p0; segtab[i].d = 1; } if(!fixshift) fixshift = 1; xscan(dst, seg, segtab, nvert, w, src, sp, detail, fixshift, clipped, op); if(detail) yscan(dst, seg, segtab, nvert, w, src, sp, fixshift, op); free(seg); free(segtab); } static long mod(long x, long y) { long z; z = x%y; if((long)(((ulong)z)^((ulong)y)) > 0 || z == 0) return z; return z + y; } static long sdiv(long x, long y) { if((long)(((ulong)x)^((ulong)y)) >= 0 || x == 0) return x/y; return (x+((y>>30)|1))/y-1; } static long smuldivmod(long x, long y, long z, long *mod) { vlong vx; if(x == 0 || y == 0){ *mod = 0; return 0; } vx = x; vx *= y; *mod = vx % z; if(*mod < 0) *mod += z; /* z is always >0 */ if((vx < 0) == (z < 0)) return vx/z; return -((-vx)/z); } static void xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op) { long y, maxy, x, x2, xerr, xden, onehalf; Seg **ep, **next, **p, **q, *s; long n, i, iy, cnt, ix, ix2, minx, maxx; Point pt; void (*fill)(Memimage*, int, int, int, Memimage*, Point, int); fill = fillline; /* * This can only work on 8-bit destinations, since fillcolor is * just using memset on sp.x. * * I'd rather not even enable it then, since then if the general * code is too slow, someone will come up with a better improvement * than this sleazy hack. -rsc * if(clipped && (src->flags&Frepl) && src->depth==8 && Dx(src->r)==1 && Dy(src->r)==1) { fill = fillcolor; sp.x = membyteval(src); } * */ USED(clipped); for(i=0, s=segtab, p=seg; ip0.y == s->p1.y) continue; if(s->p0.y > s->p1.y) { pt = s->p0; s->p0 = s->p1; s->p1 = pt; s->d = -s->d; } s->num = s->p1.x - s->p0.x; s->den = s->p1.y - s->p0.y; s->dz = sdiv(s->num, s->den) << fixshift; s->dzrem = mod(s->num, s->den) << fixshift; s->dz += sdiv(s->dzrem, s->den); s->dzrem = mod(s->dzrem, s->den); p++; } n = p-seg; if(n == 0) return; *p = 0; qsort(seg, p-seg , sizeof(Seg*), ycompare); onehalf = 0; if(fixshift) onehalf = 1 << (fixshift-1); minx = dst->clipr.min.x; maxx = dst->clipr.max.x; y = seg[0]->p0.y; if(y < (dst->clipr.min.y << fixshift)) y = dst->clipr.min.y << fixshift; iy = (y + onehalf) >> fixshift; y = (iy << fixshift) + onehalf; maxy = dst->clipr.max.y << fixshift; ep = next = seg; while(yp1.y < y) continue; s->z += s->dz; s->zerr += s->dzrem; if(s->zerr >= s->den) { s->z++; s->zerr -= s->den; if(s->zerr < 0 || s->zerr >= s->den) print("bad ratzerr1: %ld den %ld dzrem %ld\n", s->zerr, s->den, s->dzrem); } *q++ = s; } for(p = next; *p; p++) { s = *p; if(s->p0.y >= y) break; if(s->p1.y < y) continue; s->z = s->p0.x; s->z += smuldivmod(y - s->p0.y, s->num, s->den, &s->zerr); if(s->zerr < 0 || s->zerr >= s->den) print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem); *q++ = s; } ep = q; next = p; if(ep == seg) { if(*next == 0) break; iy = (next[0]->p0.y + onehalf) >> fixshift; y = (iy << fixshift) + onehalf; continue; } zsort(seg, ep); for(p = seg; p < ep; p++) { cnt = 0; x = p[0]->z; xerr = p[0]->zerr; xden = p[0]->den; ix = (x + onehalf) >> fixshift; if(ix >= maxx) break; if(ix < minx) ix = minx; cnt += p[0]->d; p++; for(;;) { if(p == ep) { print("xscan: fill to infinity"); return; } cnt += p[0]->d; if((cnt&wind) == 0) break; p++; } x2 = p[0]->z; ix2 = (x2 + onehalf) >> fixshift; if(ix2 <= minx) continue; if(ix2 > maxx) ix2 = maxx; if(ix == ix2 && detail) { if(xerr*p[0]->den + p[0]->zerr*xden > p[0]->den*xden) x++; ix = (x + x2) >> (fixshift+1); ix2 = ix+1; } (*fill)(dst, ix, ix2, iy, src, sp, op); } y += (1<p0.x == s->p1.x) continue; if(s->p0.x > s->p1.x) { pt = s->p0; s->p0 = s->p1; s->p1 = pt; s->d = -s->d; } s->num = s->p1.y - s->p0.y; s->den = s->p1.x - s->p0.x; s->dz = sdiv(s->num, s->den) << fixshift; s->dzrem = mod(s->num, s->den) << fixshift; s->dz += sdiv(s->dzrem, s->den); s->dzrem = mod(s->dzrem, s->den); p++; } n = p-seg; if(n == 0) return; *p = 0; qsort(seg, n , sizeof(Seg*), xcompare); onehalf = 0; if(fixshift) onehalf = 1 << (fixshift-1); miny = dst->clipr.min.y; maxy = dst->clipr.max.y; x = seg[0]->p0.x; if(x < (dst->clipr.min.x << fixshift)) x = dst->clipr.min.x << fixshift; ix = (x + onehalf) >> fixshift; x = (ix << fixshift) + onehalf; maxx = dst->clipr.max.x << fixshift; ep = next = seg; while(xp1.x < x) continue; s->z += s->dz; s->zerr += s->dzrem; if(s->zerr >= s->den) { s->z++; s->zerr -= s->den; if(s->zerr < 0 || s->zerr >= s->den) print("bad ratzerr1: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem); } *q++ = s; } for(p = next; *p; p++) { s = *p; if(s->p0.x >= x) break; if(s->p1.x < x) continue; s->z = s->p0.y; s->z += smuldivmod(x - s->p0.x, s->num, s->den, &s->zerr); if(s->zerr < 0 || s->zerr >= s->den) print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem); *q++ = s; } ep = q; next = p; if(ep == seg) { if(*next == 0) break; ix = (next[0]->p0.x + onehalf) >> fixshift; x = (ix << fixshift) + onehalf; continue; } zsort(seg, ep); for(p = seg; p < ep; p++) { cnt = 0; y = p[0]->z; yerr = p[0]->zerr; yden = p[0]->den; iy = (y + onehalf) >> fixshift; if(iy >= maxy) break; if(iy < miny) iy = miny; cnt += p[0]->d; p++; for(;;) { if(p == ep) { print("yscan: fill to infinity"); return; } cnt += p[0]->d; if((cnt&wind) == 0) break; p++; } y2 = p[0]->z; iy2 = (y2 + onehalf) >> fixshift; if(iy2 <= miny) continue; if(iy2 > maxy) iy2 = maxy; if(iy == iy2) { if(yerr*p[0]->den + p[0]->zerr*yden > p[0]->den*yden) y++; iy = (y + y2) >> (fixshift+1); fillpoint(dst, ix, iy, src, sp, op); } } x += (1<z > p[1]->z) { s = p[0]; p[0] = p[1]; p[1] = s; done = 0; } } } while(!done); } else { q = ep-1; for(p = seg; p < q; p++) { if(p[0]->z > p[1]->z) { qsort(seg, ep-seg, sizeof(Seg*), zcompare); break; } } } } static int ycompare(const void *a, const void *b) { Seg **s0, **s1; long y0, y1; s0 = (Seg**)a; s1 = (Seg**)b; y0 = (*s0)->p0.y; y1 = (*s1)->p0.y; if(y0 < y1) return -1; if(y0 == y1) return 0; return 1; } static int xcompare(const void *a, const void *b) { Seg **s0, **s1; long x0, x1; s0 = (Seg**)a; s1 = (Seg**)b; x0 = (*s0)->p0.x; x1 = (*s1)->p0.x; if(x0 < x1) return -1; if(x0 == x1) return 0; return 1; } static int zcompare(const void *a, const void *b) { Seg **s0, **s1; long z0, z1; s0 = (Seg**)a; s1 = (Seg**)b; z0 = (*s0)->z; z1 = (*s1)->z; if(z0 < z1) return -1; if(z0 == z1) return 0; return 1; } drawterm-20170818/libmemdraw/hwdraw.c000066400000000000000000000002371314554504700174100ustar00rootroot00000000000000#include #include #include #include int hwdraw(Memdrawparam *p) { USED(p); return 0; /* could not satisfy request */ } drawterm-20170818/libmemdraw/iprint.c000066400000000000000000000002001314554504700174070ustar00rootroot00000000000000#include #include #include #include int iprint(char *fmt,...) { USED(fmt); return -1; } drawterm-20170818/libmemdraw/line.c000066400000000000000000000254631314554504700170530ustar00rootroot00000000000000#include #include #include #include #include enum { Arrow1 = 8, Arrow2 = 10, Arrow3 = 3, }; #ifdef NOT static int lmin(int a, int b) { if(a < b) return a; return b; } #endif static int lmax(int a, int b) { if(a > b) return a; return b; } #ifdef NOTUSED /* * Rather than line clip, we run the Bresenham loop over the full line, * and clip on each pixel. This is more expensive but means that * lines look the same regardless of how the windowing has tiled them. * For speed, we check for clipping outside the loop and make the * test easy when possible. */ static void horline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr) { int x, y, dy, deltay, deltax, maxx; int dd, easy, e, bpp, m, m0; uchar *d; deltax = p1.x - p0.x; deltay = p1.y - p0.y; dd = dst->width*sizeof(ulong); dy = 1; if(deltay < 0){ dd = -dd; deltay = -deltay; dy = -1; } maxx = lmin(p1.x, clipr.max.x-1); bpp = dst->depth; m0 = 0xFF^(0xFF>>bpp); m = m0 >> (p0.x&(7/dst->depth))*bpp; easy = ptinrect(p0, clipr) && ptinrect(p1, clipr); e = 2*deltay - deltax; y = p0.y; d = byteaddr(dst, p0); deltay *= 2; deltax = deltay - 2*deltax; for(x=p0.x; x<=maxx; x++){ if(easy || (clipr.min.x<=x && clipr.min.y<=y && y 0){ y += dy; d += dd; e += deltax; }else e += deltay; d++; m >>= bpp; if(m == 0) m = m0; } } static void verline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr) { int x, y, deltay, deltax, maxy; int easy, e, bpp, m, m0, dd; uchar *d; deltax = p1.x - p0.x; deltay = p1.y - p0.y; dd = 1; if(deltax < 0){ dd = -1; deltax = -deltax; } maxy = lmin(p1.y, clipr.max.y-1); bpp = dst->depth; m0 = 0xFF^(0xFF>>bpp); m = m0 >> (p0.x&(7/dst->depth))*bpp; easy = ptinrect(p0, clipr) && ptinrect(p1, clipr); e = 2*deltax - deltay; x = p0.x; d = byteaddr(dst, p0); deltax *= 2; deltay = deltax - 2*deltay; for(y=p0.y; y<=maxy; y++){ if(easy || (clipr.min.y<=y && clipr.min.x<=x && x 0){ x += dd; d += dd; e += deltay; }else e += deltax; d += dst->width*sizeof(ulong); m >>= bpp; if(m == 0) m = m0; } } static void horliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr) { int x, y, sx, sy, deltay, deltax, minx, maxx; int bpp, m, m0; uchar *d, *s; deltax = p1.x - p0.x; deltay = p1.y - p0.y; sx = drawreplxy(src->r.min.x, src->r.max.x, p0.x+dsrc.x); minx = lmax(p0.x, clipr.min.x); maxx = lmin(p1.x, clipr.max.x-1); bpp = dst->depth; m0 = 0xFF^(0xFF>>bpp); m = m0 >> (minx&(7/dst->depth))*bpp; for(x=minx; x<=maxx; x++){ y = p0.y + (deltay*(x-p0.x)+deltax/2)/deltax; if(clipr.min.y<=y && yr.min.y, src->r.max.y, y+dsrc.y); s = byteaddr(src, Pt(sx, sy)); *d ^= (*d^*s) & m; } if(++sx >= src->r.max.x) sx = src->r.min.x; m >>= bpp; if(m == 0) m = m0; } } static void verliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr) { int x, y, sx, sy, deltay, deltax, miny, maxy; int bpp, m, m0; uchar *d, *s; deltax = p1.x - p0.x; deltay = p1.y - p0.y; sy = drawreplxy(src->r.min.y, src->r.max.y, p0.y+dsrc.y); miny = lmax(p0.y, clipr.min.y); maxy = lmin(p1.y, clipr.max.y-1); bpp = dst->depth; m0 = 0xFF^(0xFF>>bpp); for(y=miny; y<=maxy; y++){ if(deltay == 0) /* degenerate line */ x = p0.x; else x = p0.x + (deltax*(y-p0.y)+deltay/2)/deltay; if(clipr.min.x<=x && x> (x&(7/dst->depth))*bpp; d = byteaddr(dst, Pt(x, y)); sx = drawreplxy(src->r.min.x, src->r.max.x, x+dsrc.x); s = byteaddr(src, Pt(sx, sy)); *d ^= (*d^*s) & m; } if(++sy >= src->r.max.y) sy = src->r.min.y; } } static void horline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr) { int x, y, deltay, deltax, minx, maxx; int bpp, m, m0; uchar *d, *s; deltax = p1.x - p0.x; deltay = p1.y - p0.y; minx = lmax(p0.x, clipr.min.x); maxx = lmin(p1.x, clipr.max.x-1); bpp = dst->depth; m0 = 0xFF^(0xFF>>bpp); m = m0 >> (minx&(7/dst->depth))*bpp; for(x=minx; x<=maxx; x++){ y = p0.y + (deltay*(x-p0.x)+deltay/2)/deltax; if(clipr.min.y<=y && y>= bpp; if(m == 0) m = m0; } } static void verline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr) { int x, y, deltay, deltax, miny, maxy; int bpp, m, m0; uchar *d, *s; deltax = p1.x - p0.x; deltay = p1.y - p0.y; miny = lmax(p0.y, clipr.min.y); maxy = lmin(p1.y, clipr.max.y-1); bpp = dst->depth; m0 = 0xFF^(0xFF>>bpp); for(y=miny; y<=maxy; y++){ if(deltay == 0) /* degenerate line */ x = p0.x; else x = p0.x + deltax*(y-p0.y)/deltay; if(clipr.min.x<=x && x> (x&(7/dst->depth))*bpp; d = byteaddr(dst, Pt(x, y)); s = byteaddr(src, addpt(dsrc, Pt(x, y))); *d ^= (*d^*s) & m; } } } #endif /* NOTUSED */ static Memimage* membrush(int radius) { static Memimage *brush; static int brushradius; if(brush==nil || brushradius!=radius){ freememimage(brush); brush = allocmemimage(Rect(0, 0, 2*radius+1, 2*radius+1), memopaque->chan); if(brush != nil){ memfillcolor(brush, DTransparent); /* zeros */ memellipse(brush, Pt(radius, radius), radius, radius, -1, memopaque, Pt(radius, radius), S); } brushradius = radius; } return brush; } static void discend(Point p, int radius, Memimage *dst, Memimage *src, Point dsrc, int op) { Memimage *disc; Rectangle r; disc = membrush(radius); if(disc != nil){ r.min.x = p.x - radius; r.min.y = p.y - radius; r.max.x = p.x + radius+1; r.max.y = p.y + radius+1; memdraw(dst, r, src, addpt(r.min, dsrc), disc, Pt(0,0), op); } } static void arrowend(Point tip, Point *pp, int end, int sin, int cos, int radius) { int x1, x2, x3; /* before rotation */ if(end == Endarrow){ x1 = Arrow1; x2 = Arrow2; x3 = Arrow3; }else{ x1 = (end>>5) & 0x1FF; /* distance along line from end of line to tip */ x2 = (end>>14) & 0x1FF; /* distance along line from barb to tip */ x3 = (end>>23) & 0x1FF; /* distance perpendicular from edge of line to barb */ } /* comments follow track of right-facing arrowhead */ pp->x = tip.x+((2*radius+1)*sin/2-x1*cos); /* upper side of shaft */ pp->y = tip.y-((2*radius+1)*cos/2+x1*sin); pp++; pp->x = tip.x+((2*radius+2*x3+1)*sin/2-x2*cos); /* upper barb */ pp->y = tip.y-((2*radius+2*x3+1)*cos/2+x2*sin); pp++; pp->x = tip.x; pp->y = tip.y; pp++; pp->x = tip.x+(-(2*radius+2*x3+1)*sin/2-x2*cos); /* lower barb */ pp->y = tip.y-(-(2*radius+2*x3+1)*cos/2+x2*sin); pp++; pp->x = tip.x+(-(2*radius+1)*sin/2-x1*cos); /* lower side of shaft */ pp->y = tip.y+((2*radius+1)*cos/2-x1*sin); } void _memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr, int op) { /* * BUG: We should really really pick off purely horizontal and purely * vertical lines and handle them separately with calls to memimagedraw * on rectangles. */ int hor; int sin, cos, dx, dy, t; Rectangle oclipr, r; Point q, pts[10], *pp, d; if(radius < 0) return; if(rectclip(&clipr, dst->r) == 0) return; if(rectclip(&clipr, dst->clipr) == 0) return; d = subpt(sp, p0); if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0) return; if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0) return; /* this means that only verline() handles degenerate lines (p0==p1) */ hor = (abs(p1.x-p0.x) > abs(p1.y-p0.y)); /* * Clipping is a little peculiar. We can't use Sutherland-Cohen * clipping because lines are wide. But this is probably just fine: * we do all math with the original p0 and p1, but clip when deciding * what pixels to draw. This means the layer code can call this routine, * using clipr to define the region being written, and get the same set * of pixels regardless of the dicing. */ if((hor && p0.x>p1.x) || (!hor && p0.y>p1.y)){ q = p0; p0 = p1; p1 = q; t = end0; end0 = end1; end1 = t; } if((p0.x == p1.x || p0.y == p1.y) && (end0&0x1F) == Endsquare && (end1&0x1F) == Endsquare){ r.min = p0; r.max = p1; if(p0.x == p1.x){ r.min.x -= radius; r.max.x += radius+1; } else{ r.min.y -= radius; r.max.y += radius+1; } oclipr = dst->clipr; dst->clipr = clipr; memimagedraw(dst, r, src, sp, memopaque, sp, op); dst->clipr = oclipr; return; } /* Hard: */ /* draw thick line using polygon fill */ icossin2(p1.x-p0.x, p1.y-p0.y, &cos, &sin); dx = (sin*(2*radius+1))/2; dy = (cos*(2*radius+1))/2; pp = pts; oclipr = dst->clipr; dst->clipr = clipr; q.x = ICOSSCALE*p0.x+ICOSSCALE/2-cos/2; q.y = ICOSSCALE*p0.y+ICOSSCALE/2-sin/2; switch(end0 & 0x1F){ case Enddisc: discend(p0, radius, dst, src, d, op); /* fall through */ case Endsquare: default: pp->x = q.x-dx; pp->y = q.y+dy; pp++; pp->x = q.x+dx; pp->y = q.y-dy; pp++; break; case Endarrow: arrowend(q, pp, end0, -sin, -cos, radius); _memfillpolysc(dst, pts, 5, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 1, 10, 1, op); pp[1] = pp[4]; pp += 2; } q.x = ICOSSCALE*p1.x+ICOSSCALE/2+cos/2; q.y = ICOSSCALE*p1.y+ICOSSCALE/2+sin/2; switch(end1 & 0x1F){ case Enddisc: discend(p1, radius, dst, src, d, op); /* fall through */ case Endsquare: default: pp->x = q.x+dx; pp->y = q.y-dy; pp++; pp->x = q.x-dx; pp->y = q.y+dy; pp++; break; case Endarrow: arrowend(q, pp, end1, sin, cos, radius); _memfillpolysc(dst, pp, 5, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 1, 10, 1, op); pp[1] = pp[4]; pp += 2; } _memfillpolysc(dst, pts, pp-pts, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 0, 10, 1, op); dst->clipr = oclipr; return; } void memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, int op) { _memimageline(dst, p0, p1, end0, end1, radius, src, sp, dst->clipr, op); } /* * Simple-minded conservative code to compute bounding box of line. * Result is probably a little larger than it needs to be. */ static void addbbox(Rectangle *r, Point p) { if(r->min.x > p.x) r->min.x = p.x; if(r->min.y > p.y) r->min.y = p.y; if(r->max.x < p.x+1) r->max.x = p.x+1; if(r->max.y < p.y+1) r->max.y = p.y+1; } int memlineendsize(int end) { int x3; if((end&0x3F) != Endarrow) return 0; if(end == Endarrow) x3 = Arrow3; else x3 = (end>>23) & 0x1FF; return x3; } Rectangle memlinebbox(Point p0, Point p1, int end0, int end1, int radius) { Rectangle r, r1; int extra; r.min.x = 10000000; r.min.y = 10000000; r.max.x = -10000000; r.max.y = -10000000; extra = lmax(memlineendsize(end0), memlineendsize(end1)); r1 = insetrect(canonrect(Rpt(p0, p1)), -(radius+extra)); addbbox(&r, r1.min); addbbox(&r, r1.max); return r; } drawterm-20170818/libmemdraw/load.c000066400000000000000000000027301314554504700170330ustar00rootroot00000000000000#include #include #include #include int _loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) { int y, l, lpart, rpart, mx, m, mr; uchar *q; if(!rectinrect(r, i->r)) return -1; l = bytesperline(r, i->depth); if(ndata < l*Dy(r)) return -1; ndata = l*Dy(r); q = byteaddr(i, r.min); mx = 7/i->depth; lpart = (r.min.x & mx) * i->depth; rpart = (r.max.x & mx) * i->depth; m = 0xFF >> lpart; /* may need to do bit insertion on edges */ if(l == 1){ /* all in one byte */ if(rpart) m ^= 0xFF >> rpart; for(y=r.min.y; ywidth*sizeof(ulong); data++; } return ndata; } if(lpart==0 && rpart==0){ /* easy case */ for(y=r.min.y; ywidth*sizeof(ulong); data += l; } return ndata; } mr = 0xFF ^ (0xFF >> rpart); if(lpart!=0 && rpart==0){ for(y=r.min.y; y 1) memmove(q+1, data+1, l-1); q += i->width*sizeof(ulong); data += l; } return ndata; } if(lpart==0 && rpart!=0){ for(y=r.min.y; y 1) memmove(q, data, l-1); q[l-1] ^= (data[l-1]^q[l-1]) & mr; q += i->width*sizeof(ulong); data += l; } return ndata; } for(y=r.min.y; y 2) memmove(q+1, data+1, l-2); q[l-1] ^= (data[l-1]^q[l-1]) & mr; q += i->width*sizeof(ulong); data += l; } return ndata; } drawterm-20170818/libmemdraw/mkcmap.c000066400000000000000000000025621314554504700173670ustar00rootroot00000000000000#include #include #include #include /* struct Memcmap { uchar cmap2rgb[3*256]; uchar rgb2cmap[16*16*16]; }; */ static Memcmap* mkcmap(void) { static Memcmap def; int i, rgb, r, g, b; for(i=0; i<256; i++){ rgb = cmap2rgb(i); r = (rgb>>16)&0xff; g = (rgb>>8)&0xff; b = rgb&0xff; def.cmap2rgb[3*i] = r; def.cmap2rgb[3*i+1] = g; def.cmap2rgb[3*i+2] = b; } for(r=0; r<16; r++) for(g=0; g<16; g++) for(b=0; b<16; b++) def.rgb2cmap[r*16*16+g*16+b] = rgb2cmap(r*0x11, g*0x11, b*0x11); return &def; } void main(int argc, char **argv) { Memcmap *c; int i, j, inferno; inferno = 0; ARGBEGIN{ case 'i': inferno = 1; }ARGEND memimageinit(); c = mkcmap(); if(!inferno) print("#include \n#include \n"); else print("#include \"lib9.h\"\n"); print("#include \n"); print("#include \n\n"); print("static Memcmap def = {\n"); print("/* cmap2rgb */ {\n"); for(i=0; icmap2rgb); ){ print("\t"); for(j=0; j<16; j++, i++) print("0x%2.2ux,", c->cmap2rgb[i]); print("\n"); } print("},\n"); print("/* rgb2cmap */ {\n"); for(i=0; irgb2cmap);){ print("\t"); for(j=0; j<16; j++, i++) print("0x%2.2ux,", c->rgb2cmap[i]); print("\n"); } print("}\n"); print("};\n"); print("Memcmap *memdefcmap = &def;\n"); print("void _memmkcmap(void){}\n"); exits(0); } drawterm-20170818/libmemdraw/openmemsubfont.c000066400000000000000000000016041314554504700211540ustar00rootroot00000000000000#include #include #include #include Memsubfont* openmemsubfont(char *name) { Memsubfont *sf; Memimage *i; Fontchar *fc; int fd, n; char hdr[3*12+4+1]; uchar *p; fd = open(name, OREAD); if(fd < 0) return nil; p = nil; i = readmemimage(fd); if(i == nil) goto Err; if(read(fd, hdr, 3*12) != 3*12){ werrstr("openmemsubfont: header read error: %r"); goto Err; } n = atoi(hdr); p = malloc(6*(n+1)); if(p == nil) goto Err; if(read(fd, p, 6*(n+1)) != 6*(n+1)){ werrstr("openmemsubfont: fontchar read error: %r"); goto Err; } fc = malloc(sizeof(Fontchar)*(n+1)); if(fc == nil) goto Err; _unpackinfo(fc, p, n); sf = allocmemsubfont(name, n, atoi(hdr+12), atoi(hdr+24), fc, i); if(sf == nil){ free(fc); goto Err; } free(p); return sf; Err: close(fd); if (i != nil) freememimage(i); if (p != nil) free(p); return nil; } drawterm-20170818/libmemdraw/poly.c000066400000000000000000000007441314554504700171020ustar00rootroot00000000000000#include #include #include #include #include void mempoly(Memimage *dst, Point *vert, int nvert, int end0, int end1, int radius, Memimage *src, Point sp, int op) { int i, e0, e1; Point d; if(nvert < 2) return; d = subpt(sp, vert[0]); for(i=1; i #include #include #include Memimage* readmemimage(int fd) { char hdr[5*12+1]; int dy; ulong chan; uint l, n; int m, j; int new, miny, maxy; Rectangle r; uchar *tmp; int ldepth, chunk; Memimage *i; if(readn(fd, hdr, 11) != 11){ werrstr("readimage: short header"); return nil; } if(memcmp(hdr, "compressed\n", 11) == 0) return creadmemimage(fd); if(readn(fd, hdr+11, 5*12-11) != 5*12-11){ werrstr("readimage: short header (2)"); return nil; } /* * distinguish new channel descriptor from old ldepth. * channel descriptors have letters as well as numbers, * while ldepths are a single digit formatted as %-11d. */ new = 0; for(m=0; m<10; m++){ if(hdr[m] != ' '){ new = 1; break; } } if(hdr[11] != ' '){ werrstr("readimage: bad format"); return nil; } if(new){ hdr[11] = '\0'; if((chan = strtochan(hdr)) == 0){ werrstr("readimage: bad channel string %s", hdr); return nil; } }else{ ldepth = ((int)hdr[10])-'0'; if(ldepth<0 || ldepth>3){ werrstr("readimage: bad ldepth %d", ldepth); return nil; } chan = drawld2chan[ldepth]; } r.min.x = atoi(hdr+1*12); r.min.y = atoi(hdr+2*12); r.max.x = atoi(hdr+3*12); r.max.y = atoi(hdr+4*12); if(r.min.x>r.max.x || r.min.y>r.max.y){ werrstr("readimage: bad rectangle"); return nil; } miny = r.min.y; maxy = r.max.y; l = bytesperline(r, chantodepth(chan)); i = allocmemimage(r, chan); if(i == nil) return nil; chunk = 32*1024; if(chunk < l) chunk = l; tmp = malloc(chunk); if(tmp == nil) goto Err; while(maxy > miny){ dy = maxy - miny; if(dy*l > chunk) dy = chunk/l; if(dy <= 0){ werrstr("readmemimage: image too wide for buffer"); goto Err; } n = dy*l; m = readn(fd, tmp, n); if(m != n){ werrstr("readmemimage: read count %d not %d: %r", m, n); Err: freememimage(i); free(tmp); return nil; } if(!new) /* an old image: must flip all the bits */ for(j=0; j #include #include #include #include Point memimagestring(Memimage *b, Point p, Memimage *color, Point cp, Memsubfont *f, char *cs) { int w, width; uchar *s; Rune c; Fontchar *i; s = (uchar*)cs; for(; (c=*s); p.x+=width, cp.x+=width){ width = 0; if(c < Runeself) s++; else{ w = chartorune(&c, (char*)s); if(w == 0){ s++; continue; } s += w; } if(c >= f->n) continue; // i = f->info+c; i = &(f->info[c]); width = i->width; memdraw(b, Rect(p.x+i->left, p.y+i->top, p.x+i->left+(i[1].x-i[0].x), p.y+i->bottom), color, cp, f->bits, Pt(i->x, i->top), SoverD); } return p; } Point memsubfontwidth(Memsubfont *f, char *cs) { Rune c; Point p; uchar *s; Fontchar *i; int w, width; p = Pt(0, f->height); s = (uchar*)cs; for(; (c=*s); p.x+=width){ width = 0; if(c < Runeself) s++; else{ w = chartorune(&c, (char*)s); if(w == 0){ s++; continue; } s += w; } if(c >= f->n) continue; i = f->info+c; width = i->width; } return p; } drawterm-20170818/libmemdraw/subfont.c000066400000000000000000000010611314554504700175700ustar00rootroot00000000000000#include #include #include #include Memsubfont* allocmemsubfont(char *name, int n, int height, int ascent, Fontchar *info, Memimage *i) { Memsubfont *f; f = malloc(sizeof(Memsubfont)); if(f == 0) return 0; f->n = n; f->height = height; f->ascent = ascent; f->info = info; f->bits = i; if(name) f->name = strdup(name); else f->name = 0; return f; } void freememsubfont(Memsubfont *f) { if(f == 0) return; free(f->info); /* note: f->info must have been malloc'ed! */ freememimage(f->bits); free(f); } drawterm-20170818/libmemdraw/times000066400000000000000000000011121314554504700170050ustar00rootroot00000000000000draw1: 6M for draw 0,0,100,100 no repl draw3: 4M for draw 0,0,100,100 no repl just read src, dst - 250k mask reading - 650k write dst - 100k alpha calculation - 3000k olddraw: 10M for draw 0, 0, 1000, 1000 no repl all ldepth 3 44M for draw 0, 0, 1000, 1000 src, mask ldepth 2 dst ldepth 3 draw4: 160M for draw 0, 0, 1000, 1000 no repl all r8g8b8 null loop: 10k src, dst reading: 13-15M each mask reading: 30M alpha calculation loop: 90M null alpha loop: 2M minimal loop control +20M alpha calculation with divides +190M alpha calculation wtih shifts +70M writeback: 11M drawterm-20170818/libmemdraw/unload.c000066400000000000000000000006631314554504700174010ustar00rootroot00000000000000#include #include #include #include int unloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) { int y, l; uchar *q; if(!rectinrect(r, i->r)) return -1; l = bytesperline(r, i->depth); if(ndata < l*Dy(r)) return -1; ndata = l*Dy(r); q = byteaddr(i, r.min); for(y=r.min.y; ywidth*sizeof(ulong); data += l; } return ndata; } drawterm-20170818/libmemdraw/write.c000066400000000000000000000104271314554504700172500ustar00rootroot00000000000000#include #include #include #include #define CHUNK 8000 #define HSHIFT 3 /* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */ #define NHASH (1<<(HSHIFT*NMATCH)) #define HMASK (NHASH-1) #define hupdate(h, c) ((((h)<r; bpl = bytesperline(r, i->depth); n = Dy(r)*bpl; data = malloc(n); ncblock = _compblocksize(r, i->depth); outbuf = malloc(ncblock); hash = malloc(NHASH*sizeof(Hlist)); chain = malloc(NMEM*sizeof(Hlist)); if(data == 0 || outbuf == 0 || hash == 0 || chain == 0){ ErrOut: free(data); free(outbuf); free(hash); free(chain); return -1; } for(miny = r.min.y; miny != r.max.y; miny += dy){ dy = r.max.y-miny; if(dy*bpl > CHUNK) dy = CHUNK/bpl; nb = unloadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), data+(miny-r.min.y)*bpl, dy*bpl); if(nb != dy*bpl) goto ErrOut; } sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ", chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y); if(write(fd, hdr, 11+5*12) != 11+5*12) goto ErrOut; edata = data+n; eout = outbuf+ncblock; line = data; r.max.y = r.min.y; while(line != edata){ memset(hash, 0, NHASH*sizeof(Hlist)); memset(chain, 0, NMEM*sizeof(Hlist)); cp = chain; h = 0; outp = outbuf; for(n = 0; n != NMATCH; n++) h = hupdate(h, line[n]); loutp = outbuf; while(line != edata){ ndump = 0; eline = line+bpl; for(p = line; p != eline; ){ if(eline-p < NRUN) es = eline; else es = p+NRUN; q = 0; runlen = 0; for(hp = hash[h].next; hp; hp = hp->next){ s = p + runlen; if(s >= es) continue; t = hp->s + runlen; for(; s >= p; s--) if(*s != *t--) goto matchloop; t += runlen+2; s += runlen+2; for(; s < es; s++) if(*s != *t++) break; n = s-p; if(n > runlen){ runlen = n; q = hp->s; if(n == NRUN) break; } matchloop: ; } if(runlen < NMATCH){ if(ndump == NDUMP){ if(eout-outp < ndump+1) goto Bfull; *outp++ = ndump-1+128; memmove(outp, dumpbuf, ndump); outp += ndump; ndump = 0; } dumpbuf[ndump++] = *p; runlen = 1; } else{ if(ndump != 0){ if(eout-outp < ndump+1) goto Bfull; *outp++ = ndump-1+128; memmove(outp, dumpbuf, ndump); outp += ndump; ndump = 0; } offs = p-q-1; if(eout-outp < 2) goto Bfull; *outp++ = ((runlen-NMATCH)<<2) + (offs>>8); *outp++ = offs&255; } for(q = p+runlen; p != q; p++){ if(cp->prev) cp->prev->next = 0; cp->next = hash[h].next; cp->prev = &hash[h]; if(cp->next) cp->next->prev = cp; cp->prev->next = cp; cp->s = p; if(++cp == &chain[NMEM]) cp = chain; if(edata-p > NMATCH) h = hupdate(h, p[NMATCH]); } } if(ndump != 0){ if(eout-outp < ndump+1) goto Bfull; *outp++ = ndump-1+128; memmove(outp, dumpbuf, ndump); outp += ndump; } line = eline; loutp = outp; r.max.y++; } Bfull: if(loutp == outbuf) goto ErrOut; n = loutp-outbuf; sprint(hdr, "%11d %11ld ", r.max.y, n); write(fd, hdr, 2*12); write(fd, outbuf, n); r.min.y = r.max.y; } free(data); free(outbuf); free(hash); free(chain); return 0; } drawterm-20170818/libmemlayer/000077500000000000000000000000001314554504700161255ustar00rootroot00000000000000drawterm-20170818/libmemlayer/Makefile000066400000000000000000000004771314554504700175750ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libmemlayer.a OFILES=\ draw.$O\ lalloc.$O\ layerop.$O\ ldelete.$O\ lhide.$O\ line.$O\ load.$O\ lorigin.$O\ lsetrefresh.$O\ ltofront.$O\ ltorear.$O\ unload.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/libmemlayer/draw.c000066400000000000000000000077401314554504700172360ustar00rootroot00000000000000#include #include #include #include #include struct Draw { Point deltas; Point deltam; Memlayer *dstlayer; Memimage *src; Memimage *mask; int op; }; static void ldrawop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave) { struct Draw *d; Point p0, p1; Rectangle oclipr, srcr, r, mr; int ok; d = etc; if(insave && d->dstlayer->save==nil) return; p0 = addpt(screenr.min, d->deltas); p1 = addpt(screenr.min, d->deltam); if(insave){ r = rectsubpt(screenr, d->dstlayer->delta); clipr = rectsubpt(clipr, d->dstlayer->delta); }else r = screenr; /* now in logical coordinates */ /* clipr may have narrowed what we should draw on, so clip if necessary */ if(!rectinrect(r, clipr)){ oclipr = dst->clipr; dst->clipr = clipr; ok = drawclip(dst, &r, d->src, &p0, d->mask, &p1, &srcr, &mr); dst->clipr = oclipr; if(!ok) return; } memdraw(dst, r, d->src, p0, d->mask, p1, d->op); } void memdraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op) { struct Draw d; Rectangle srcr, tr, mr; Memlayer *dl, *sl; if(drawdebug) iprint("memdraw %p %R %p %P %p %P\n", dst, r, src, p0, mask, p1); if(mask == nil) mask = memopaque; if(mask->layer){ if(drawdebug) iprint("mask->layer != nil\n"); return; /* too hard, at least for now */ } Top: if(dst->layer==nil && src->layer==nil){ memimagedraw(dst, r, src, p0, mask, p1, op); return; } if(drawclip(dst, &r, src, &p0, mask, &p1, &srcr, &mr) == 0){ if(drawdebug) iprint("drawclip dstcr %R srccr %R maskcr %R\n", dst->clipr, src->clipr, mask->clipr); return; } /* * Convert to screen coordinates. */ dl = dst->layer; if(dl != nil){ r.min.x += dl->delta.x; r.min.y += dl->delta.y; r.max.x += dl->delta.x; r.max.y += dl->delta.y; } Clearlayer: if(dl!=nil && dl->clear){ if(src == dst){ p0.x += dl->delta.x; p0.y += dl->delta.y; src = dl->screen->image; } dst = dl->screen->image; goto Top; } sl = src->layer; if(sl != nil){ p0.x += sl->delta.x; p0.y += sl->delta.y; srcr.min.x += sl->delta.x; srcr.min.y += sl->delta.y; srcr.max.x += sl->delta.x; srcr.max.y += sl->delta.y; } /* * Now everything is in screen coordinates. * mask is an image. dst and src are images or obscured layers. */ /* * if dst and src are the same layer, just draw in save area and expose. */ if(dl!=nil && dst==src){ if(dl->save == nil) return; /* refresh function makes this case unworkable */ if(rectXrect(r, srcr)){ tr = r; if(srcr.min.x < tr.min.x){ p1.x += tr.min.x - srcr.min.x; tr.min.x = srcr.min.x; } if(srcr.min.y < tr.min.y){ p1.y += tr.min.x - srcr.min.x; tr.min.y = srcr.min.y; } if(srcr.max.x > tr.max.x) tr.max.x = srcr.max.x; if(srcr.max.y > tr.max.y) tr.max.y = srcr.max.y; memlhide(dst, tr); }else{ memlhide(dst, r); memlhide(dst, srcr); } memdraw(dl->save, rectsubpt(r, dl->delta), dl->save, subpt(srcr.min, src->layer->delta), mask, p1, op); memlexpose(dst, r); return; } if(sl){ if(sl->clear){ src = sl->screen->image; if(dl != nil){ r.min.x -= dl->delta.x; r.min.y -= dl->delta.y; r.max.x -= dl->delta.x; r.max.y -= dl->delta.y; } goto Top; } /* relatively rare case; use save area */ if(sl->save == nil) return; /* refresh function makes this case unworkable */ memlhide(src, srcr); /* convert back to logical coordinates */ p0.x -= sl->delta.x; p0.y -= sl->delta.y; srcr.min.x -= sl->delta.x; srcr.min.y -= sl->delta.y; srcr.max.x -= sl->delta.x; srcr.max.y -= sl->delta.y; src = src->layer->save; } /* * src is now an image. dst may be an image or a clear layer */ if(dst->layer==nil) goto Top; if(dst->layer->clear) goto Clearlayer; /* * dst is an obscured layer */ d.deltas = subpt(p0, r.min); d.deltam = subpt(p1, r.min); d.dstlayer = dl; d.src = src; d.op = op; d.mask = mask; _memlayerop(ldrawop, dst, r, r, &d); } drawterm-20170818/libmemlayer/lalloc.c000066400000000000000000000034021314554504700175360ustar00rootroot00000000000000#include #include #include #include #include Memimage* memlalloc(Memscreen *s, Rectangle screenr, Refreshfn refreshfn, void *refreshptr, ulong val) { Memlayer *l; Memimage *n; static Memimage *paint; if(paint == nil){ paint = allocmemimage(Rect(0,0,1,1), RGBA32); if(paint == nil) return nil; paint->flags |= Frepl; paint->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); } n = allocmemimaged(screenr, s->image->chan, s->image->data, s->image->X); if(n == nil) return nil; l = malloc(sizeof(Memlayer)); if(l == nil){ free(n); return nil; } l->screen = s; if(refreshfn) l->save = nil; else{ l->save = allocmemimage(screenr, s->image->chan); if(l->save == nil){ free(l); free(n); return nil; } /* allocmemimage doesn't initialize memory; this paints save area */ if(val != DNofill) memfillcolor(l->save, val); } l->refreshfn = refreshfn; l->refreshptr = nil; /* don't set it until we're done */ l->screenr = screenr; l->delta = Pt(0,0); n->data->ref++; n->zero = s->image->zero; n->width = s->image->width; n->layer = l; /* start with new window behind all existing ones */ l->front = s->rearmost; l->rear = nil; if(s->rearmost) s->rearmost->layer->rear = n; s->rearmost = n; if(s->frontmost == nil) s->frontmost = n; l->clear = 0; /* now pull new window to front */ _memltofrontfill(n, val != DNofill); l->refreshptr = refreshptr; /* * paint with requested color; previously exposed areas are already right * if this window has backing store, but just painting the whole thing is simplest. */ if(val != DNofill){ memsetchan(paint, n->chan); memfillcolor(paint, val); memdraw(n, n->r, paint, n->r.min, nil, n->r.min, S); } return n; } drawterm-20170818/libmemlayer/layerop.c000066400000000000000000000051211314554504700177430ustar00rootroot00000000000000#include #include #include #include #include #define RECUR(a,b,c,d) _layerop(fn, i, Rect(a.x, b.y, c.x, d.y), clipr, etc, front->layer->rear); static void _layerop( void (*fn)(Memimage*, Rectangle, Rectangle, void*, int), Memimage *i, Rectangle r, Rectangle clipr, void *etc, Memimage *front) { Rectangle fr; Top: if(front == i){ /* no one is in front of this part of window; use the screen */ fn(i->layer->screen->image, r, clipr, etc, 0); return; } fr = front->layer->screenr; if(rectXrect(r, fr) == 0){ /* r doesn't touch this window; continue on next rearmost */ // assert(front && front->layer && front->layer->screen && front->layer->rear); front = front->layer->rear; goto Top; } if(fr.max.y < r.max.y){ RECUR(r.min, fr.max, r.max, r.max); r.max.y = fr.max.y; } if(r.min.y < fr.min.y){ RECUR(r.min, r.min, r.max, fr.min); r.min.y = fr.min.y; } if(fr.max.x < r.max.x){ RECUR(fr.max, r.min, r.max, r.max); r.max.x = fr.max.x; } if(r.min.x < fr.min.x){ RECUR(r.min, r.min, fr.min, r.max); r.min.x = fr.min.x; } /* r is covered by front, so put in save area */ (*fn)(i->layer->save, r, clipr, etc, 1); } /* * Assumes incoming rectangle has already been clipped to i's logical r and clipr */ void _memlayerop( void (*fn)(Memimage*, Rectangle, Rectangle, void*, int), Memimage *i, Rectangle screenr, /* clipped to window boundaries */ Rectangle clipr, /* clipped also to clipping rectangles of hierarchy */ void *etc) { Memlayer *l; Rectangle r, scr; l = i->layer; if(!rectclip(&screenr, l->screenr)) return; if(l->clear){ fn(l->screen->image, screenr, clipr, etc, 0); return; } r = screenr; scr = l->screen->image->clipr; /* * Do the piece on the screen */ if(rectclip(&screenr, scr)) _layerop(fn, i, screenr, clipr, etc, l->screen->frontmost); if(rectinrect(r, scr)) return; /* * Do the piece off the screen */ if(!rectXrect(r, scr)){ /* completely offscreen; easy */ fn(l->save, r, clipr, etc, 1); return; } if(r.min.y < scr.min.y){ /* above screen */ fn(l->save, Rect(r.min.x, r.min.y, r.max.x, scr.min.y), clipr, etc, 1); r.min.y = scr.min.y; } if(r.max.y > scr.max.y){ /* below screen */ fn(l->save, Rect(r.min.x, scr.max.y, r.max.x, r.max.y), clipr, etc, 1); r.max.y = scr.max.y; } if(r.min.x < scr.min.x){ /* left of screen */ fn(l->save, Rect(r.min.x, r.min.y, scr.min.x, r.max.y), clipr, etc, 1); r.min.x = scr.min.x; } if(r.max.x > scr.max.x){ /* right of screen */ fn(l->save, Rect(scr.max.x, r.min.y, r.max.x, r.max.y), clipr, etc, 1); } } drawterm-20170818/libmemlayer/ldelete.c000066400000000000000000000022371314554504700177130ustar00rootroot00000000000000#include #include #include #include #include void memldelete(Memimage *i) { Memscreen *s; Memlayer *l; l = i->layer; /* free backing store and disconnect refresh, to make pushback fast */ freememimage(l->save); l->save = nil; l->refreshptr = nil; memltorear(i); /* window is now the rearmost; clean up screen structures and deallocate */ s = i->layer->screen; if(s->fill){ i->clipr = i->r; memdraw(i, i->r, s->fill, i->r.min, nil, i->r.min, S); } if(l->front){ l->front->layer->rear = nil; s->rearmost = l->front; }else{ s->frontmost = nil; s->rearmost = nil; } free(l); freememimage(i); } /* * Just free the data structures, don't do graphics */ void memlfree(Memimage *i) { Memlayer *l; l = i->layer; freememimage(l->save); free(l); freememimage(i); } void _memlsetclear(Memscreen *s) { Memimage *i, *j; Memlayer *l; for(i=s->rearmost; i; i=i->layer->front){ l = i->layer; l->clear = rectinrect(l->screenr, l->screen->image->clipr); if(l->clear) for(j=l->front; j; j=j->layer->front) if(rectXrect(l->screenr, j->layer->screenr)){ l->clear = 0; break; } } } drawterm-20170818/libmemlayer/lhide.c000066400000000000000000000032131314554504700173550ustar00rootroot00000000000000#include #include #include #include #include /* * Hide puts that portion of screenr now on the screen into the window's save area. * Expose puts that portion of screenr now in the save area onto the screen. * * Hide and Expose both require that the layer structures in the screen * match the geometry they are being asked to update, that is, they update the * save area (hide) or screen (expose) based on what those structures tell them. * This means they must be called at the correct time during window shuffles. */ static void lhideop(Memimage *src, Rectangle screenr, Rectangle clipr, void *etc, int insave) { Rectangle r; Memlayer *l; USED(clipr.min.x); USED(insave); l = etc; if(src != l->save){ /* do nothing if src is already in save area */ r = rectsubpt(screenr, l->delta); memdraw(l->save, r, src, screenr.min, nil, screenr.min, S); } } void memlhide(Memimage *i, Rectangle screenr) { if(i->layer->save == nil) return; if(rectclip(&screenr, i->layer->screen->image->r) == 0) return; _memlayerop(lhideop, i, screenr, screenr, i->layer); } static void lexposeop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave) { Memlayer *l; Rectangle r; USED(clipr.min.x); if(insave) /* if dst is save area, don't bother */ return; l = etc; r = rectsubpt(screenr, l->delta); if(l->save) memdraw(dst, screenr, l->save, r.min, nil, r.min, S); else l->refreshfn(dst, r, l->refreshptr); } void memlexpose(Memimage *i, Rectangle screenr) { if(rectclip(&screenr, i->layer->screen->image->r) == 0) return; _memlayerop(lexposeop, i, screenr, screenr, i->layer); } drawterm-20170818/libmemlayer/line.c000066400000000000000000000050331314554504700172210ustar00rootroot00000000000000#include #include #include #include #include struct Lline { Point p0; Point p1; Point delta; int end0; int end1; int radius; Point sp; Memlayer *dstlayer; Memimage *src; int op; }; static void llineop(Memimage*, Rectangle, Rectangle, void*, int); static void _memline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr, int op) { Rectangle r; struct Lline ll; Point d; int srcclipped; Memlayer *dl; if(radius < 0) return; if(src->layer) /* can't draw line with layered source */ return; srcclipped = 0; Top: dl = dst->layer; if(dl == nil){ _memimageline(dst, p0, p1, end0, end1, radius, src, sp, clipr, op); return; } if(!srcclipped){ d = subpt(sp, p0); if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0) return; if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0) return; srcclipped = 1; } /* dst is known to be a layer */ p0.x += dl->delta.x; p0.y += dl->delta.y; p1.x += dl->delta.x; p1.y += dl->delta.y; clipr.min.x += dl->delta.x; clipr.min.y += dl->delta.y; clipr.max.x += dl->delta.x; clipr.max.y += dl->delta.y; if(dl->clear){ dst = dst->layer->screen->image; goto Top; } /* XXX */ /* this is not the correct set of tests */ // if(log2[dst->depth] != log2[src->depth] || log2[dst->depth]!=3) // return; /* can't use sutherland-cohen clipping because lines are wide */ r = memlinebbox(p0, p1, end0, end1, radius); /* * r is now a bounding box for the line; * use it as a clipping rectangle for subdivision */ if(rectclip(&r, clipr) == 0) return; ll.p0 = p0; ll.p1 = p1; ll.end0 = end0; ll.end1 = end1; ll.sp = sp; ll.dstlayer = dst->layer; ll.src = src; ll.radius = radius; ll.delta = dl->delta; ll.op = op; _memlayerop(llineop, dst, r, r, &ll); } static void llineop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave) { struct Lline *ll; Point p0, p1; USED(screenr.min.x); ll = etc; if(insave && ll->dstlayer->save==nil) return; if(!rectclip(&clipr, screenr)) return; if(insave){ p0 = subpt(ll->p0, ll->delta); p1 = subpt(ll->p1, ll->delta); clipr = rectsubpt(clipr, ll->delta); }else{ p0 = ll->p0; p1 = ll->p1; } _memline(dst, p0, p1, ll->end0, ll->end1, ll->radius, ll->src, ll->sp, clipr, ll->op); } void memline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, int op) { _memline(dst, p0, p1, end0, end1, radius, src, sp, dst->clipr, op); } drawterm-20170818/libmemlayer/load.c000066400000000000000000000020101314554504700172010ustar00rootroot00000000000000#include #include #include #include #include int memload(Memimage *dst, Rectangle r, uchar *data, int n, int iscompressed) { int (*loadfn)(Memimage*, Rectangle, uchar*, int); Memimage *tmp; Memlayer *dl; Rectangle lr; int dx; loadfn = loadmemimage; if(iscompressed) loadfn = cloadmemimage; Top: dl = dst->layer; if(dl == nil) return loadfn(dst, r, data, n); /* * Convert to screen coordinates. */ lr = r; r.min.x += dl->delta.x; r.min.y += dl->delta.y; r.max.x += dl->delta.x; r.max.y += dl->delta.y; dx = dl->delta.x&(7/dst->depth); if(dl->clear && dx==0){ dst = dl->screen->image; goto Top; } /* * dst is an obscured layer or data is unaligned */ if(dl->save && dx==0){ n = loadfn(dl->save, lr, data, n); if(n > 0) memlexpose(dst, r); return n; } tmp = allocmemimage(lr, dst->chan); if(tmp == nil) return -1; n = loadfn(tmp, lr, data, n); memdraw(dst, lr, tmp, lr.min, nil, lr.min, S); freememimage(tmp); return n; } drawterm-20170818/libmemlayer/lorigin.c000066400000000000000000000047131314554504700177410ustar00rootroot00000000000000#include #include #include #include #include /* * Place i so i->r.min = log, i->layer->screenr.min == scr. */ int memlorigin(Memimage *i, Point log, Point scr) { Memlayer *l; Memscreen *s; Memimage *t, *shad, *nsave; Rectangle x, newr, oldr; Point delta; int overlap, eqlog, eqscr, wasclear; l = i->layer; s = l->screen; oldr = l->screenr; newr = Rect(scr.x, scr.y, scr.x+Dx(oldr), scr.y+Dy(oldr)); eqscr = eqpt(scr, oldr.min); eqlog = eqpt(log, i->r.min); if(eqscr && eqlog) return 0; nsave = nil; if(eqlog==0 && l->save!=nil){ nsave = allocmemimage(Rect(log.x, log.y, log.x+Dx(oldr), log.y+Dy(oldr)), i->chan); if(nsave == nil) return -1; } /* * Bring it to front and move logical coordinate system. */ memltofront(i); wasclear = l->clear; if(nsave){ if(!wasclear) memimagedraw(nsave, nsave->r, l->save, l->save->r.min, nil, Pt(0,0), S); freememimage(l->save); l->save = nsave; } delta = subpt(log, i->r.min); i->r = rectaddpt(i->r, delta); i->clipr = rectaddpt(i->clipr, delta); l->delta = subpt(l->screenr.min, i->r.min); if(eqscr) return 0; /* * To clean up old position, make a shadow window there, don't paint it, * push it behind this one, and (later) delete it. Because the refresh function * for this fake window is a no-op, this will cause no graphics action except * to restore the background and expose the windows previously hidden. */ shad = memlalloc(s, oldr, memlnorefresh, nil, DNofill); if(shad == nil) return -1; s->frontmost = i; if(s->rearmost == i) s->rearmost = shad; else l->rear->layer->front = shad; shad->layer->front = i; shad->layer->rear = l->rear; l->rear = shad; l->front = nil; shad->layer->clear = 0; /* * Shadow is now holding down the fort at the old position. * Move the window and hide things obscured by new position. */ for(t=l->rear->layer->rear; t!=nil; t=t->layer->rear){ x = newr; overlap = rectclip(&x, t->layer->screenr); if(overlap){ memlhide(t, x); t->layer->clear = 0; } } l->screenr = newr; l->delta = subpt(scr, i->r.min); l->clear = rectinrect(newr, l->screen->image->clipr); /* * Everything's covered. Copy to new position and delete shadow window. */ if(wasclear) memdraw(s->image, newr, s->image, oldr.min, nil, Pt(0,0), S); else memlexpose(i, newr); memldelete(shad); return 1; } void memlnorefresh(Memimage *l, Rectangle r, void *v) { USED(l); USED(r.min.x); USED(v); } drawterm-20170818/libmemlayer/lsetrefresh.c000066400000000000000000000012671314554504700206250ustar00rootroot00000000000000#include #include #include #include #include int memlsetrefresh(Memimage *i, Refreshfn fn, void *ptr) { Memlayer *l; l = i->layer; if(l->refreshfn!=0 && fn!=0){ /* just change functions */ l->refreshfn = fn; l->refreshptr = ptr; return 1; } if(l->refreshfn == 0){ /* is using backup image; just free it */ freememimage(l->save); l->save = nil; l->refreshfn = fn; l->refreshptr = ptr; return 1; } l->save = allocmemimage(i->r, i->chan); if(l->save == nil) return 0; /* easiest way is just to update the entire save area */ l->refreshfn(i, i->r, l->refreshptr); l->refreshfn = 0; l->refreshptr = nil; return 1; } drawterm-20170818/libmemlayer/ltofront.c000066400000000000000000000024111314554504700201360ustar00rootroot00000000000000#include #include #include #include #include /* * Pull i towards top of screen, just behind front */ static void _memltofront(Memimage *i, Memimage *front, int fill) { Memlayer *l; Memscreen *s; Memimage *f, *ff, *rr; Rectangle x; int overlap; l = i->layer; s = l->screen; while(l->front != front){ f = l->front; x = l->screenr; overlap = rectclip(&x, f->layer->screenr); if(overlap){ memlhide(f, x); f->layer->clear = 0; } /* swap l and f in screen's list */ ff = f->layer->front; rr = l->rear; if(ff == nil) s->frontmost = i; else ff->layer->rear = i; if(rr == nil) s->rearmost = f; else rr->layer->front = f; l->front = ff; l->rear = f; f->layer->front = i; f->layer->rear = rr; if(overlap && fill) memlexpose(i, x); } } void _memltofrontfill(Memimage *i, int fill) { _memltofront(i, nil, fill); _memlsetclear(i->layer->screen); } void memltofront(Memimage *i) { _memltofront(i, nil, 1); _memlsetclear(i->layer->screen); } void memltofrontn(Memimage **ip, int n) { Memimage *i, *front; Memscreen *s; if(n == 0) return; front = nil; while(--n >= 0){ i = *ip++; _memltofront(i, front, 1); front = i; } s = front->layer->screen; _memlsetclear(s); } drawterm-20170818/libmemlayer/ltorear.c000066400000000000000000000020461314554504700177430ustar00rootroot00000000000000#include #include #include #include #include void _memltorear(Memimage *i, Memimage *rear) { Memlayer *l; Memscreen *s; Memimage *f, *r, *rr; Rectangle x; int overlap; l = i->layer; s = l->screen; while(l->rear != rear){ r = l->rear; x = l->screenr; overlap = rectclip(&x, r->layer->screenr); if(overlap){ memlhide(i, x); l->clear = 0; } /* swap l and r in screen's list */ rr = r->layer->rear; f = l->front; if(rr == nil) s->rearmost = i; else rr->layer->front = i; if(f == nil) s->frontmost = r; else f->layer->rear = r; l->rear = rr; l->front = r; r->layer->rear = i; r->layer->front = f; if(overlap) memlexpose(r, x); } } void memltorear(Memimage *i) { _memltorear(i, nil); _memlsetclear(i->layer->screen); } void memltorearn(Memimage **ip, int n) { Memimage *i, *rear; Memscreen *s; if(n == 0) return; rear = nil; while(--n >= 0){ i = *ip++; _memltorear(i, rear); rear = i; } s = rear->layer->screen; _memlsetclear(s); } drawterm-20170818/libmemlayer/unload.c000066400000000000000000000017551314554504700175630ustar00rootroot00000000000000#include #include #include #include #include int memunload(Memimage *src, Rectangle r, uchar *data, int n) { Memimage *tmp; Memlayer *dl; Rectangle lr; int dx; Top: dl = src->layer; if(dl == nil) return unloadmemimage(src, r, data, n); /* * Convert to screen coordinates. */ lr = r; r.min.x += dl->delta.x; r.min.y += dl->delta.y; r.max.x += dl->delta.x; r.max.y += dl->delta.y; dx = dl->delta.x&(7/src->depth); if(dl->clear && dx==0){ src = dl->screen->image; goto Top; } /* * src is an obscured layer or data is unaligned */ if(dl->save && dx==0){ if(dl->refreshfn != 0) return -1; /* can't unload window if it's not Refbackup */ if(n > 0) memlhide(src, r); n = unloadmemimage(dl->save, lr, data, n); return n; } tmp = allocmemimage(lr, src->chan); if(tmp == nil) return -1; memdraw(tmp, lr, src, lr.min, nil, lr.min, S); n = unloadmemimage(tmp, lr, data, n); freememimage(tmp); return n; } drawterm-20170818/libmp/000077500000000000000000000000001314554504700147265ustar00rootroot00000000000000drawterm-20170818/libmp/Makefile000066400000000000000000000011321314554504700163630ustar00rootroot00000000000000ROOT=.. include ../Make.config # N.B. This is used only for secstore. It needn't be fast. LIB=libmp.a OFILES=\ betomp.$O\ crt.$O\ letomp.$O\ mpadd.$O\ mpaux.$O\ mpcmp.$O\ mpdigdiv.$O\ mpdiv.$O\ mpeuclid.$O\ mpexp.$O\ mpextendedgcd.$O\ mpfmt.$O\ mpinvert.$O\ mpleft.$O\ mpmod.$O\ mpmul.$O\ mprand.$O\ mpright.$O\ mpsub.$O\ mptobe.$O\ mptoi.$O\ mptole.$O\ mptoui.$O\ mptouv.$O\ mptov.$O\ mpvecadd.$O\ mpveccmp.$O\ mpvecdigmuladd.$O\ mpvecsub.$O\ strtomp.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/libmp/betomp.c000066400000000000000000000011011314554504700163510ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // convert a big-endian byte array (most significant byte first) to an mpint mpint* betomp(uchar *p, uint n, mpint *b) { int m, s; mpdigit x; if(b == nil) b = mpnew(0); // dump leading zeros while(*p == 0 && n > 1){ p++; n--; } // get the space mpbits(b, n*8); b->top = DIGITS(n*8); m = b->top-1; // first digit might not be Dbytes long s = ((n-1)*8)%Dbits; x = 0; for(; n > 0; n--){ x |= ((mpdigit)(*p++)) << s; s -= 8; if(s < 0){ b->p[m--] = x; s = Dbits-8; x = 0; } } return b; } drawterm-20170818/libmp/crt.c000066400000000000000000000040021314554504700156560ustar00rootroot00000000000000#include "os.h" #include #include // chinese remainder theorem // // handbook of applied cryptography, menezes et al, 1997, pp 610 - 613 struct CRTpre { int n; // number of moduli mpint **m; // pointer to moduli mpint **c; // precomputed coefficients mpint **p; // precomputed products mpint *a[1]; // local storage }; // setup crt info, returns a newly created structure CRTpre* crtpre(int n, mpint **m) { CRTpre *crt; int i, j; mpint *u; crt = malloc(sizeof(CRTpre)+sizeof(mpint)*3*n); if(crt == nil) sysfatal("crtpre: %r"); crt->m = crt->a; crt->c = crt->a+n; crt->p = crt->c+n; crt->n = n; // make a copy of the moduli for(i = 0; i < n; i++) crt->m[i] = mpcopy(m[i]); // precompute the products u = mpcopy(mpone); for(i = 0; i < n; i++){ mpmul(u, m[i], u); crt->p[i] = mpcopy(u); } // precompute the coefficients for(i = 1; i < n; i++){ crt->c[i] = mpcopy(mpone); for(j = 0; j < i; j++){ mpinvert(m[j], m[i], u); mpmul(u, crt->c[i], u); mpmod(u, m[i], crt->c[i]); } } mpfree(u); return crt; } void crtprefree(CRTpre *crt) { int i; for(i = 0; i < crt->n; i++){ if(i != 0) mpfree(crt->c[i]); mpfree(crt->p[i]); mpfree(crt->m[i]); } free(crt); } // convert to residues, returns a newly created structure CRTres* crtin(CRTpre *crt, mpint *x) { int i; CRTres *res; res = malloc(sizeof(CRTres)+sizeof(mpint)*crt->n); if(res == nil) sysfatal("crtin: %r"); res->n = crt->n; for(i = 0; i < res->n; i++){ res->r[i] = mpnew(0); mpmod(x, crt->m[i], res->r[i]); } return res; } // garners algorithm for converting residue form to linear void crtout(CRTpre *crt, CRTres *res, mpint *x) { mpint *u; int i; u = mpnew(0); mpassign(res->r[0], x); for(i = 1; i < crt->n; i++){ mpsub(res->r[i], x, u); mpmul(u, crt->c[i], u); mpmod(u, crt->m[i], u); mpmul(u, crt->p[i-1], u); mpadd(x, u, x); } mpfree(u); } // free the residue void crtresfree(CRTres *res) { int i; for(i = 0; i < res->n; i++) mpfree(res->r[i]); free(res); } drawterm-20170818/libmp/crttest.c000066400000000000000000000014551314554504700165670ustar00rootroot00000000000000#include "os.h" #include #include void testcrt(mpint **p) { CRTpre *crt; CRTres *res; mpint *m, *x, *y; int i; fmtinstall('B', mpconv); // get a modulus and a test number m = mpnew(1024+160); mpmul(p[0], p[1], m); x = mpnew(1024+160); mpadd(m, mpone, x); // do the precomputation for crt conversion crt = crtpre(2, p); // convert x to residues res = crtin(crt, x); // convert back y = mpnew(1024+160); crtout(crt, res, y); print("x %B\ny %B\n", x, y); mpfree(m); mpfree(x); mpfree(y); } void main(void) { int i; mpint *p[2]; long start; start = time(0); for(i = 0; i < 10; i++){ p[0] = mpnew(1024); p[1] = mpnew(1024); DSAprimes(p[0], p[1], nil); testcrt(p); mpfree(p[0]); mpfree(p[1]); } print("%d secs with more\n", time(0)-start); exits(0); } drawterm-20170818/libmp/dat.h000066400000000000000000000007211314554504700156470ustar00rootroot00000000000000#define mpdighi (mpdigit)(1U<<(Dbits-1)) #define DIGITS(x) ((Dbits - 1 + (x))/Dbits) // for converting between int's and mpint's #define MAXUINT ((uint)-1) #define MAXINT (MAXUINT>>1) #define MININT (MAXINT+1) // for converting between vlongs's and mpint's // #define MAXUVLONG (~0ULL) // #define MAXVLONG (MAXUVLONG>>1) // #define MINVLONG (MAXVLONG+1ULL) #define MAXUVLONG ((uvlong) ~0) #define MAXVLONG (MAXUVLONG>>1) #define MINVLONG (MAXVLONG+((uvlong) 1)) drawterm-20170818/libmp/letomp.c000066400000000000000000000007071314554504700163760ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // convert a little endian byte array (least significant byte first) to an mpint mpint* letomp(uchar *s, uint n, mpint *b) { int i=0, m = 0; mpdigit x=0; if(b == nil) b = mpnew(0); mpbits(b, 8*n); b->top = DIGITS(8*n); for(; n > 0; n--){ x |= ((mpdigit)(*s++)) << i; i += 8; if(i == Dbits){ b->p[m++] = x; i = 0; x = 0; } } if(i > 0) b->p[m++] = x; b->top = m; return b; } drawterm-20170818/libmp/mpadd.c000066400000000000000000000014171314554504700161620ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // sum = abs(b1) + abs(b2), i.e., add the magnitudes void mpmagadd(mpint *b1, mpint *b2, mpint *sum) { int m, n; mpint *t; // get the sizes right if(b2->top > b1->top){ t = b1; b1 = b2; b2 = t; } n = b1->top; m = b2->top; if(n == 0){ mpassign(mpzero, sum); return; } if(m == 0){ mpassign(b1, sum); return; } mpbits(sum, (n+1)*Dbits); sum->top = n+1; mpvecadd(b1->p, n, b2->p, m, sum->p); sum->sign = 1; mpnorm(sum); } // sum = b1 + b2 void mpadd(mpint *b1, mpint *b2, mpint *sum) { int sign; if(b1->sign != b2->sign){ if(b1->sign < 0) mpmagsub(b2, b1, sum); else mpmagsub(b1, b2, sum); } else { sign = b1->sign; mpmagadd(b1, b2, sum); if(sum->top != 0) sum->sign = sign; } } drawterm-20170818/libmp/mpaux.c000066400000000000000000000047741314554504700162400ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" static mpdigit _mptwodata[1] = { 2 }; static mpint _mptwo = { 1, 1, 1, _mptwodata, MPstatic }; mpint *mptwo = &_mptwo; static mpdigit _mponedata[1] = { 1 }; static mpint _mpone = { 1, 1, 1, _mponedata, MPstatic }; mpint *mpone = &_mpone; static mpdigit _mpzerodata[1] = { 0 }; static mpint _mpzero = { 1, 1, 0, _mpzerodata, MPstatic }; mpint *mpzero = &_mpzero; static int mpmindigits = 33; // set minimum digit allocation void mpsetminbits(int n) { if(n == 0) n = 1; mpmindigits = DIGITS(n); } // allocate an n bit 0'd number mpint* mpnew(int n) { mpint *b; b = mallocz(sizeof(mpint), 1); if(b == nil) sysfatal("mpnew: %r"); n = DIGITS(n); if(n < mpmindigits) n = mpmindigits; b->p = (mpdigit*)mallocz(n*Dbytes, 1); if(b->p == nil) sysfatal("mpnew: %r"); b->size = n; b->sign = 1; return b; } // guarantee at least n significant bits void mpbits(mpint *b, int m) { int n; n = DIGITS(m); if(b->size >= n){ if(b->top >= n) return; memset(&b->p[b->top], 0, Dbytes*(n - b->top)); b->top = n; return; } b->p = (mpdigit*)realloc(b->p, n*Dbytes); if(b->p == nil) sysfatal("mpbits: %r"); memset(&b->p[b->top], 0, Dbytes*(n - b->top)); b->size = n; b->top = n; } void mpfree(mpint *b) { if(b == nil) return; if(b->flags & MPstatic) sysfatal("freeing mp constant"); memset(b->p, 0, b->top*Dbytes); // information hiding free(b->p); free(b); } void mpnorm(mpint *b) { int i; for(i = b->top-1; i >= 0; i--) if(b->p[i] != 0) break; b->top = i+1; if(b->top == 0) b->sign = 1; } mpint* mpcopy(mpint *old) { mpint *new; new = mpnew(Dbits*old->size); new->top = old->top; new->sign = old->sign; memmove(new->p, old->p, Dbytes*old->top); return new; } void mpassign(mpint *old, mpint *new) { mpbits(new, Dbits*old->top); new->sign = old->sign; new->top = old->top; memmove(new->p, old->p, Dbytes*old->top); } // number of significant bits in mantissa int mpsignif(mpint *n) { int i, j; mpdigit d; if(n->top == 0) return 0; for(i = n->top-1; i >= 0; i--){ d = n->p[i]; for(j = Dbits-1; j >= 0; j--){ if(d & (((mpdigit)1)<top==0) return 0; k = 0; bit = 0; digit = 0; d = n->p[0]; for(;;){ if(d & (1<= n->top) return 0; d = n->p[digit]; bit = 0; } } return k; } drawterm-20170818/libmp/mpcmp.c000066400000000000000000000007161314554504700162120ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // return 1, 0, -1 as abs(b1)-abs(b2) is neg, 0, pos int mpmagcmp(mpint *b1, mpint *b2) { int i; i = b1->top - b2->top; if(i) return i; return mpveccmp(b1->p, b1->top, b2->p, b2->top); } // return neg, 0, pos as b1-b2 is neg, 0, pos int mpcmp(mpint *b1, mpint *b2) { if(b1->sign != b2->sign) return b1->sign - b2->sign; if(b1->sign < 0) return mpmagcmp(b2, b1); else return mpmagcmp(b1, b2); } drawterm-20170818/libmp/mpdigdiv.c000066400000000000000000000013341314554504700166760ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // // divide two digits by one and return quotient // void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient) { mpdigit hi, lo, q, x, y; int i; hi = dividend[1]; lo = dividend[0]; // return highest digit value if the result >= 2**32 if(hi >= divisor || divisor == 0){ divisor = 0; *quotient = ~divisor; return; } // at this point we know that hi < divisor // just shift and subtract till we're done q = 0; x = divisor; for(i = Dbits-1; hi > 0 && i >= 0; i--){ x >>= 1; if(x > hi) continue; y = divisor< lo) continue; if(y > lo) hi--; lo -= y; hi -= x; q |= 1< #include "dat.h" // division ala knuth, seminumerical algorithms, pp 237-238 // the numbers are stored backwards to what knuth expects so j // counts down rather than up. void mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder) { int j, s, vn, sign; mpdigit qd, *up, *vp, *qp; mpint *u, *v, *t; // divide bv zero if(divisor->top == 0) abort(); // quick check if(mpmagcmp(dividend, divisor) < 0){ if(remainder != nil) mpassign(dividend, remainder); if(quotient != nil) mpassign(mpzero, quotient); return; } // D1: shift until divisor, v, has hi bit set (needed to make trial // divisor accurate) qd = divisor->p[divisor->top-1]; for(s = 0; (qd & mpdighi) == 0; s++) qd <<= 1; u = mpnew((dividend->top+2)*Dbits + s); if(s == 0 && divisor != quotient && divisor != remainder) { mpassign(dividend, u); v = divisor; } else { mpleft(dividend, s, u); v = mpnew(divisor->top*Dbits); mpleft(divisor, s, v); } up = u->p+u->top-1; vp = v->p+v->top-1; vn = v->top; // D1a: make sure high digit of dividend is less than high digit of divisor if(*up >= *vp){ *++up = 0; u->top++; } // storage for multiplies t = mpnew(4*Dbits); qp = nil; if(quotient != nil){ mpbits(quotient, (u->top - v->top)*Dbits); quotient->top = u->top - v->top; qp = quotient->p+quotient->top-1; } // D2, D7: loop on length of dividend for(j = u->top; j > vn; j--){ // D3: calculate trial divisor mpdigdiv(up-1, *vp, &qd); // D3a: rule out trial divisors 2 greater than real divisor if(vn > 1) for(;;){ memset(t->p, 0, 3*Dbytes); // mpvecdigmuladd adds to what's there mpvecdigmuladd(vp-1, 2, qd, t->p); if(mpveccmp(t->p, 3, up-2, 3) > 0) qd--; else break; } // D4: u -= v*qd << j*Dbits sign = mpvecdigmulsub(v->p, vn, qd, up-vn); if(sign < 0){ // D6: trial divisor was too high, add back borrowed // value and decrease divisor mpvecadd(up-vn, vn+1, v->p, vn, up-vn); qd--; } // D5: save quotient digit if(qp != nil) *qp-- = qd; // push top of u down one u->top--; *up-- = 0; } if(qp != nil){ mpnorm(quotient); if(dividend->sign != divisor->sign) quotient->sign = -1; } if(remainder != nil){ mpright(u, s, remainder); // u is the remainder shifted remainder->sign = dividend->sign; } mpfree(t); mpfree(u); if(v != divisor) mpfree(v); } drawterm-20170818/libmp/mpeuclid.c000066400000000000000000000023121314554504700166720ustar00rootroot00000000000000#include "os.h" #include // extended euclid // // For a and b it solves, d = gcd(a,b) and finds x and y s.t. // ax + by = d // // Handbook of Applied Cryptography, Menezes et al, 1997, pg 67 void mpeuclid(mpint *a, mpint *b, mpint *d, mpint *x, mpint *y) { mpint *tmp, *x0, *x1, *x2, *y0, *y1, *y2, *q, *r; if(mpcmp(a, b) < 0){ tmp = a; a = b; b = tmp; tmp = x; x = y; y = tmp; } if(b->top == 0){ mpassign(a, d); mpassign(mpone, x); mpassign(mpzero, y); return; } a = mpcopy(a); b = mpcopy(b); x0 = mpnew(0); x1 = mpcopy(mpzero); x2 = mpcopy(mpone); y0 = mpnew(0); y1 = mpcopy(mpone); y2 = mpcopy(mpzero); q = mpnew(0); r = mpnew(0); while(b->top != 0 && b->sign > 0){ // q = a/b // r = a mod b mpdiv(a, b, q, r); // x0 = x2 - qx1 mpmul(q, x1, x0); mpsub(x2, x0, x0); // y0 = y2 - qy1 mpmul(q, y1, y0); mpsub(y2, y0, y0); // rotate values tmp = a; a = b; b = r; r = tmp; tmp = x2; x2 = x1; x1 = x0; x0 = tmp; tmp = y2; y2 = y1; y1 = y0; y0 = tmp; } mpassign(a, d); mpassign(x2, x); mpassign(y2, y); mpfree(x0); mpfree(x1); mpfree(x2); mpfree(y0); mpfree(y1); mpfree(y2); mpfree(q); mpfree(r); mpfree(a); mpfree(b); } drawterm-20170818/libmp/mpexp.c000066400000000000000000000021751314554504700162300ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // res = b**e // // knuth, vol 2, pp 398-400 enum { Freeb= 0x1, Freee= 0x2, Freem= 0x4, }; //int expdebug; void mpexp(mpint *b, mpint *e, mpint *m, mpint *res) { mpint *t[2]; int tofree; mpdigit d, bit; int i, j; t[0] = mpcopy(b); t[1] = res; tofree = 0; if(res == b){ b = mpcopy(b); tofree |= Freeb; } if(res == e){ e = mpcopy(e); tofree |= Freee; } if(res == m){ m = mpcopy(m); tofree |= Freem; } // skip first bit i = e->top-1; d = e->p[i]; for(bit = mpdighi; (bit & d) == 0; bit >>= 1) ; bit >>= 1; j = 0; for(;;){ for(; bit != 0; bit >>= 1){ mpmul(t[j], t[j], t[j^1]); if(bit & d) mpmul(t[j^1], b, t[j]); else j ^= 1; if(m != nil && t[j]->top > m->top){ mpmod(t[j], m, t[j^1]); j ^= 1; } } if(--i < 0) break; bit = mpdighi; d = e->p[i]; } if(m != nil){ mpmod(t[j], m, t[j^1]); j ^= 1; } if(t[j] == res){ mpfree(t[j^1]); } else { mpassign(t[j], res); mpfree(t[j]); } if(tofree){ if(tofree & Freeb) mpfree(b); if(tofree & Freee) mpfree(e); if(tofree & Freem) mpfree(m); } } drawterm-20170818/libmp/mpextendedgcd.c000066400000000000000000000031151314554504700177050ustar00rootroot00000000000000#include "os.h" #include #define iseven(a) (((a)->p[0] & 1) == 0) // extended binary gcd // // For a anv b it solves, v = gcd(a,b) and finds x and y s.t. // ax + by = v // // Handbook of Applied Cryptography, Menezes et al, 1997, pg 608. void mpextendedgcd(mpint *a, mpint *b, mpint *v, mpint *x, mpint *y) { mpint *u, *A, *B, *C, *D; int g; if(a->top == 0){ mpassign(b, v); mpassign(mpone, y); mpassign(mpzero, x); return; } if(b->top == 0){ mpassign(a, v); mpassign(mpone, x); mpassign(mpzero, y); return; } g = 0; a = mpcopy(a); b = mpcopy(b); while(iseven(a) && iseven(b)){ mpright(a, 1, a); mpright(b, 1, b); g++; } u = mpcopy(a); mpassign(b, v); A = mpcopy(mpone); B = mpcopy(mpzero); C = mpcopy(mpzero); D = mpcopy(mpone); for(;;) { // print("%B %B %B %B %B %B\n", u, v, A, B, C, D); while(iseven(u)){ mpright(u, 1, u); if(!iseven(A) || !iseven(B)) { mpadd(A, b, A); mpsub(B, a, B); } mpright(A, 1, A); mpright(B, 1, B); } // print("%B %B %B %B %B %B\n", u, v, A, B, C, D); while(iseven(v)){ mpright(v, 1, v); if(!iseven(C) || !iseven(D)) { mpadd(C, b, C); mpsub(D, a, D); } mpright(C, 1, C); mpright(D, 1, D); } // print("%B %B %B %B %B %B\n", u, v, A, B, C, D); if(mpcmp(u, v) >= 0){ mpsub(u, v, u); mpsub(A, C, A); mpsub(B, D, B); } else { mpsub(v, u, v); mpsub(C, A, C); mpsub(D, B, D); } if(u->top == 0) break; } mpassign(C, x); mpassign(D, y); mpleft(v, g, v); mpfree(A); mpfree(B); mpfree(C); mpfree(D); mpfree(u); mpfree(a); mpfree(b); } drawterm-20170818/libmp/mpfmt.c000066400000000000000000000052511314554504700162200ustar00rootroot00000000000000#include "os.h" #include #include #include "dat.h" static int to64(mpint *b, char *buf, int len) { uchar *p; int n, rv; p = nil; n = mptobe(b, nil, 0, &p); if(n < 0) return -1; rv = enc64(buf, len, p, n); free(p); return rv; } static int to32(mpint *b, char *buf, int len) { uchar *p; int n, rv; // leave room for a multiple of 5 buffer size n = b->top*Dbytes + 5; p = malloc(n); if(p == nil) return -1; n = mptobe(b, p, n, nil); if(n < 0) return -1; // round up buffer size, enc32 only accepts a multiple of 5 if(n%5) n += 5 - (n%5); rv = enc32(buf, len, p, n); free(p); return rv; } static char set16[] = "0123456789ABCDEF"; static int to16(mpint *b, char *buf, int len) { mpdigit *p, x; int i, j; char *out, *eout; if(len < 1) return -1; out = buf; eout = buf+len; for(p = &b->p[b->top-1]; p >= b->p; p--){ x = *p; for(i = Dbits-4; i >= 0; i -= 4){ j = 0xf & (x>>i); if(j != 0 || out != buf){ if(out >= eout) return -1; *out++ = set16[j]; } } } if(out == buf) *out++ = '0'; if(out >= eout) return -1; *out = 0; return 0; } static char* modbillion(int rem, ulong r, char *out, char *buf) { ulong rr; int i; for(i = 0; i < 9; i++){ rr = r%10; r /= 10; if(out <= buf) return nil; *--out = '0' + rr; if(rem == 0 && r == 0) break; } return out; } static int to10(mpint *b, char *buf, int len) { mpint *d, *r, *billion; char *out; if(len < 1) return -1; d = mpcopy(b); r = mpnew(0); billion = uitomp(1000000000, nil); out = buf+len; *--out = 0; do { mpdiv(d, billion, d, r); out = modbillion(d->top, r->p[0], out, buf); if(out == nil) break; } while(d->top != 0); mpfree(d); mpfree(r); mpfree(billion); if(out == nil) return -1; len -= out-buf; if(out != buf) memmove(buf, out, len); return 0; } int mpfmt(Fmt *fmt) { mpint *b; char *p; b = va_arg(fmt->args, mpint*); if(b == nil) return fmtstrcpy(fmt, "*"); p = mptoa(b, fmt->prec, nil, 0); fmt->flags &= ~FmtPrec; if(p == nil) return fmtstrcpy(fmt, "*"); else{ fmtstrcpy(fmt, p); free(p); return 0; } } char* mptoa(mpint *b, int base, char *buf, int len) { char *out; int rv, alloced; alloced = 0; if(buf == nil){ len = ((b->top+1)*Dbits+2)/3 + 1; buf = malloc(len); if(buf == nil) return nil; alloced = 1; } if(len < 2) return nil; out = buf; if(b->sign < 0){ *out++ = '-'; len--; } switch(base){ case 64: rv = to64(b, out, len); break; case 32: rv = to32(b, out, len); break; default: case 16: rv = to16(b, out, len); break; case 10: rv = to10(b, out, len); break; } if(rv < 0){ if(alloced) free(buf); return nil; } return buf; } drawterm-20170818/libmp/mpinvert.c000066400000000000000000000006121314554504700167350ustar00rootroot00000000000000#include "os.h" #include #define iseven(a) (((a)->p[0] & 1) == 0) // use extended gcd to find the multiplicative inverse // res = b**-1 mod m void mpinvert(mpint *b, mpint *m, mpint *res) { mpint *dc1, *dc2; // don't care dc1 = mpnew(0); dc2 = mpnew(0); mpextendedgcd(b, m, dc1, res, dc2); if(mpcmp(dc1, mpone) != 0) abort(); mpmod(res, m, res); mpfree(dc1); mpfree(dc2); } drawterm-20170818/libmp/mpleft.c000066400000000000000000000015061314554504700163630ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // res = b << shift void mpleft(mpint *b, int shift, mpint *res) { int d, l, r, i, otop; mpdigit this, last; // a negative left shift is a right shift if(shift < 0){ mpright(b, -shift, res); return; } // b and res may be the same so remember the old top otop = b->top; // shift mpbits(res, otop*Dbits + shift); // overkill res->top = DIGITS(otop*Dbits + shift); d = shift/Dbits; l = shift - d*Dbits; r = Dbits - l; if(l == 0){ for(i = otop-1; i >= 0; i--) res->p[i+d] = b->p[i]; } else { last = 0; for(i = otop-1; i >= 0; i--) { this = b->p[i]; res->p[i+d+1] = (last<>r); last = this; } res->p[d] = last<p[i] = 0; // normalize while(res->top > 0 && res->p[res->top-1] == 0) res->top--; } drawterm-20170818/libmp/mpmod.c000066400000000000000000000003671314554504700162140ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // remainder = b mod m // // knuth, vol 2, pp 398-400 void mpmod(mpint *b, mpint *m, mpint *remainder) { mpdiv(b, m, nil, remainder); if(remainder->sign < 0) mpadd(m, remainder, remainder); } drawterm-20170818/libmp/mpmul.c000066400000000000000000000060461314554504700162320ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // // from knuth's 1969 seminumberical algorithms, pp 233-235 and pp 258-260 // // mpvecmul is an assembly language routine that performs the inner // loop. // // the karatsuba trade off is set empiricly by measuring the algs on // a 400 MHz Pentium II. // // karatsuba like (see knuth pg 258) // prereq: p is already zeroed static void mpkaratsuba(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p) { mpdigit *t, *u0, *u1, *v0, *v1, *u0v0, *u1v1, *res, *diffprod; int u0len, u1len, v0len, v1len, reslen; int sign, n; // divide each piece in half n = alen/2; if(alen&1) n++; u0len = n; u1len = alen-n; if(blen > n){ v0len = n; v1len = blen-n; } else { v0len = blen; v1len = 0; } u0 = a; u1 = a + u0len; v0 = b; v1 = b + v0len; // room for the partial products t = mallocz(Dbytes*5*(2*n+1), 1); if(t == nil) sysfatal("mpkaratsuba: %r"); u0v0 = t; u1v1 = t + (2*n+1); diffprod = t + 2*(2*n+1); res = t + 3*(2*n+1); reslen = 4*n+1; // t[0] = (u1-u0) sign = 1; if(mpveccmp(u1, u1len, u0, u0len) < 0){ sign = -1; mpvecsub(u0, u0len, u1, u1len, u0v0); } else mpvecsub(u1, u1len, u0, u1len, u0v0); // t[1] = (v0-v1) if(mpveccmp(v0, v0len, v1, v1len) < 0){ sign *= -1; mpvecsub(v1, v1len, v0, v1len, u1v1); } else mpvecsub(v0, v0len, v1, v1len, u1v1); // t[4:5] = (u1-u0)*(v0-v1) mpvecmul(u0v0, u0len, u1v1, v0len, diffprod); // t[0:1] = u1*v1 memset(t, 0, 2*(2*n+1)*Dbytes); if(v1len > 0) mpvecmul(u1, u1len, v1, v1len, u1v1); // t[2:3] = u0v0 mpvecmul(u0, u0len, v0, v0len, u0v0); // res = u0*v0< 0){ mpvecadd(res+n, reslen-n, u1v1, u1len+v1len, res+n); mpvecadd(res+2*n, reslen-2*n, u1v1, u1len+v1len, res+2*n); } // res += (u1-u0)*(v0-v1)<= KARATSUBAMIN && blen > 1){ // O(n^1.585) mpkaratsuba(a, alen, b, blen, p); } else { // O(n^2) for(i = 0; i < blen; i++){ d = b[i]; if(d != 0) mpvecdigmuladd(a, alen, d, &p[i]); } } } void mpmul(mpint *b1, mpint *b2, mpint *prod) { mpint *oprod; oprod = nil; if(prod == b1 || prod == b2){ oprod = prod; prod = mpnew(0); } prod->top = 0; mpbits(prod, (b1->top+b2->top+1)*Dbits); mpvecmul(b1->p, b1->top, b2->p, b2->top, prod->p); prod->top = b1->top+b2->top+1; prod->sign = b1->sign*b2->sign; mpnorm(prod); if(oprod != nil){ mpassign(prod, oprod); mpfree(prod); } } drawterm-20170818/libmp/mprand.c000066400000000000000000000011101314554504700163440ustar00rootroot00000000000000#include "os.h" #include #include #include "dat.h" mpint* mprand(int bits, void (*gen)(uchar*, int), mpint *b) { int n, m; mpdigit mask; uchar *p; n = DIGITS(bits); if(b == nil) b = mpnew(bits); else mpbits(b, bits); p = malloc(n*Dbytes); if(p == nil) return nil; (*gen)(p, n*Dbytes); betomp(p, n*Dbytes, b); free(p); // make sure we don't give too many bits m = bits%Dbits; n--; if(m > 0){ mask = 1; mask <<= m; mask--; b->p[n] &= mask; } for(; n >= 0; n--) if(b->p[n] != 0) break; b->top = n+1; b->sign = 1; return b; } drawterm-20170818/libmp/mpright.c000066400000000000000000000012671314554504700165520ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // res = b >> shift void mpright(mpint *b, int shift, mpint *res) { int d, l, r, i; mpdigit this, last; // a negative right shift is a left shift if(shift < 0){ mpleft(b, -shift, res); return; } if(res != b) mpbits(res, b->top*Dbits - shift); d = shift/Dbits; r = shift - d*Dbits; l = Dbits - r; // special case digit shifts if(r == 0){ for(i = 0; i < b->top-d; i++) res->p[i] = b->p[i+d]; } else { last = b->p[d]; for(i = 0; i < b->top-d-1; i++){ this = b->p[i+d+1]; res->p[i] = (this<>r); last = this; } res->p[i++] = last>>r; } while(i > 0 && res->p[i-1] == 0) i--; res->top = i; } drawterm-20170818/libmp/mpsub.c000066400000000000000000000014301314554504700162160ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // diff = abs(b1) - abs(b2), i.e., subtract the magnitudes void mpmagsub(mpint *b1, mpint *b2, mpint *diff) { int n, m, sign; mpint *t; // get the sizes right if(mpmagcmp(b1, b2) < 0){ sign = -1; t = b1; b1 = b2; b2 = t; } else sign = 1; n = b1->top; m = b2->top; if(m == 0){ mpassign(b1, diff); diff->sign = sign; return; } mpbits(diff, n*Dbits); mpvecsub(b1->p, n, b2->p, m, diff->p); diff->sign = sign; diff->top = n; mpnorm(diff); } // diff = b1 - b2 void mpsub(mpint *b1, mpint *b2, mpint *diff) { int sign; if(b1->sign != b2->sign){ sign = b1->sign; mpmagadd(b1, b2, diff); diff->sign = sign; return; } sign = b1->sign; mpmagsub(b1, b2, diff); if(diff->top != 0) diff->sign *= sign; } drawterm-20170818/libmp/mptobe.c000066400000000000000000000015571314554504700163700ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // convert an mpint into a big endian byte array (most significant byte first) // return number of bytes converted // if p == nil, allocate and result array int mptobe(mpint *b, uchar *p, uint n, uchar **pp) { int i, j, suppress; mpdigit x; uchar *e, *s, c; if(p == nil){ n = (b->top+1)*Dbytes; p = malloc(n); } if(p == nil) return -1; if(pp != nil) *pp = p; memset(p, 0, n); // special case 0 if(b->top == 0){ if(n < 1) return -1; else return 1; } s = p; e = s+n; suppress = 1; for(i = b->top-1; i >= 0; i--){ x = b->p[i]; for(j = Dbits-8; j >= 0; j -= 8){ c = x>>j; if(c == 0 && suppress) continue; if(p >= e) return -1; *p++ = c; suppress = 0; } } // guarantee at least one byte if(s == p){ if(p >= e) return -1; *p++ = 0; } return p - s; } drawterm-20170818/libmp/mptoi.c000066400000000000000000000010511314554504700162170ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" /* * this code assumes that mpdigit is at least as * big as an int. */ mpint* itomp(int i, mpint *b) { if(b == nil) b = mpnew(0); mpassign(mpzero, b); if(i != 0) b->top = 1; if(i < 0){ b->sign = -1; *b->p = -i; } else *b->p = i; return b; } int mptoi(mpint *b) { uint x; x = *b->p; if(b->sign > 0){ if(b->top > 1 || (x > MAXINT)) x = (int)MAXINT; else x = (int)x; } else { if(b->top > 1 || x > MAXINT+1) x = (int)MININT; else x = -(int)x; } return x; } drawterm-20170818/libmp/mptole.c000066400000000000000000000014221314554504700163710ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // convert an mpint into a little endian byte array (least significant byte first) // return number of bytes converted // if p == nil, allocate and result array int mptole(mpint *b, uchar *p, uint n, uchar **pp) { int i, j; mpdigit x; uchar *e, *s; if(p == nil){ n = (b->top+1)*Dbytes; p = malloc(n); } if(pp != nil) *pp = p; if(p == nil) return -1; memset(p, 0, n); // special case 0 if(b->top == 0){ if(n < 1) return -1; else return 0; } s = p; e = s+n; for(i = 0; i < b->top-1; i++){ x = b->p[i]; for(j = 0; j < Dbytes; j++){ if(p >= e) return -1; *p++ = x; x >>= 8; } } x = b->p[i]; while(x > 0){ if(p >= e) return -1; *p++ = x; x >>= 8; } return p - s; } drawterm-20170818/libmp/mptoui.c000066400000000000000000000006351314554504700164130ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" /* * this code assumes that mpdigit is at least as * big as an int. */ mpint* uitomp(uint i, mpint *b) { if(b == nil) b = mpnew(0); mpassign(mpzero, b); if(i != 0) b->top = 1; *b->p = i; return b; } uint mptoui(mpint *b) { uint x; x = *b->p; if(b->sign < 0){ x = 0; } else { if(b->top > 1 || x > MAXUINT) x = MAXUINT; } return x; } drawterm-20170818/libmp/mptouv.c000066400000000000000000000013271314554504700164270ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" #define VLDIGITS (sizeof(vlong)/sizeof(mpdigit)) /* * this code assumes that a vlong is an integral number of * mpdigits long. */ mpint* uvtomp(uvlong v, mpint *b) { int s; if(b == nil) b = mpnew(VLDIGITS*sizeof(mpdigit)); else mpbits(b, VLDIGITS*sizeof(mpdigit)); mpassign(mpzero, b); if(v == 0) return b; for(s = 0; s < VLDIGITS && v != 0; s++){ b->p[s] = v; v >>= sizeof(mpdigit)*8; } b->top = s; return b; } uvlong mptouv(mpint *b) { uvlong v; int s; if(b->top == 0) return (vlong) 0; mpnorm(b); if(b->top > VLDIGITS) return MAXVLONG; v = (uvlong) 0; for(s = 0; s < b->top; s++) v |= b->p[s]<<(s*sizeof(mpdigit)*8); return v; } drawterm-20170818/libmp/mptov.c000066400000000000000000000017431314554504700162440ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" #define VLDIGITS (sizeof(vlong)/sizeof(mpdigit)) /* * this code assumes that a vlong is an integral number of * mpdigits long. */ mpint* vtomp(vlong v, mpint *b) { int s; uvlong uv; if(b == nil) b = mpnew(VLDIGITS*sizeof(mpdigit)); else mpbits(b, VLDIGITS*sizeof(mpdigit)); mpassign(mpzero, b); if(v == 0) return b; if(v < 0){ b->sign = -1; uv = -v; } else uv = v; for(s = 0; s < VLDIGITS && uv != 0; s++){ b->p[s] = uv; uv >>= sizeof(mpdigit)*8; } b->top = s; return b; } vlong mptov(mpint *b) { uvlong v; int s; if(b->top == 0) return (vlong) 0; mpnorm(b); if(b->top > VLDIGITS){ if(b->sign > 0) return (vlong)MAXVLONG; else return (vlong)MINVLONG; } v = (uvlong) 0; for(s = 0; s < b->top; s++) v |= b->p[s]<<(s*sizeof(mpdigit)*8); if(b->sign > 0){ if(v > MAXVLONG) v = MAXVLONG; } else { if(v > MINVLONG) v = MINVLONG; else v = -(vlong)v; } return (vlong)v; } drawterm-20170818/libmp/mpvecadd.c000066400000000000000000000010071314554504700166530ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // prereq: alen >= blen, sum has at least blen+1 digits void mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum) { int i, carry; mpdigit x, y; carry = 0; for(i = 0; i < blen; i++){ x = *a++; y = *b++; x += carry; if(x < carry) carry = 1; else carry = 0; x += y; if(x < y) carry++; *sum++ = x; } for(; i < alen; i++){ x = *a++ + carry; if(x < carry) carry = 1; else carry = 0; *sum++ = x; } *sum = carry; } drawterm-20170818/libmp/mpveccmp.c000066400000000000000000000006221314554504700167040ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // prereq: alen >= blen int mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen) { mpdigit x; while(alen > blen) if(a[--alen] != 0) return 1; while(blen > alen) if(b[--blen] != 0) return -1; while(alen > 0){ --alen; x = a[alen] - b[alen]; if(x == 0) continue; if(x > a[alen]) return -1; else return 1; } return 0; } drawterm-20170818/libmp/mpvecdigmuladd.c000066400000000000000000000030561314554504700200630ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" #define LO(x) ((x) & ((1<<(Dbits/2))-1)) #define HI(x) ((x) >> (Dbits/2)) static void mpdigmul(mpdigit a, mpdigit b, mpdigit *p) { mpdigit x, ah, al, bh, bl, p1, p2, p3, p4; int carry; // half digits ah = HI(a); al = LO(a); bh = HI(b); bl = LO(b); // partial products p1 = ah*bl; p2 = bh*al; p3 = bl*al; p4 = ah*bh; // p = ((p1+p2)<<(Dbits/2)) + (p4< x) borrow = 1; else borrow = 0; x = part[1]; mpdigmul(*b++, m, part); x += part[0]; if(x < part[0]) borrow++; x = y - x; if(x > y) borrow++; *p++ = x; } x = *p; y = x - borrow - part[1]; *p = y; if(y > x) return -1; else return 1; } drawterm-20170818/libmp/mpvecsub.c000066400000000000000000000010131314554504700167110ustar00rootroot00000000000000#include "os.h" #include #include "dat.h" // prereq: a >= b, alen >= blen, diff has at least alen digits void mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff) { int i, borrow; mpdigit x, y; borrow = 0; for(i = 0; i < blen; i++){ x = *a++; y = *b++; y += borrow; if(y < borrow) borrow = 1; else borrow = 0; if(x < y) borrow++; *diff++ = x - y; } for(; i < alen; i++){ x = *a++; y = x - borrow; if(y > x) borrow = 1; else borrow = 0; *diff++ = y; } } drawterm-20170818/libmp/os.h000066400000000000000000000000421314554504700155140ustar00rootroot00000000000000#include #include drawterm-20170818/libmp/reduce000066400000000000000000000004621314554504700161220ustar00rootroot00000000000000O=$1 shift objtype=$1 shift ls -p ../$objtype/*.[cs] >[2]/dev/null | sed 's/..$//' > /tmp/reduce.$pid # # if empty directory, just return the input files # if (! ~ $status '|') { echo $* rm /tmp/reduce.$pid exit 0 } echo $* | tr ' ' \012 | grep -v -f /tmp/reduce.$pid | tr \012 ' ' rm /tmp/reduce.$pid drawterm-20170818/libmp/strtomp.c000066400000000000000000000057221314554504700166100ustar00rootroot00000000000000#include "os.h" #include #include #include "dat.h" static struct { int inited; uchar t64[256]; uchar t32[256]; uchar t16[256]; uchar t10[256]; } tab; enum { INVAL= 255 }; static char set64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static char set32[] = "23456789abcdefghijkmnpqrstuvwxyz"; static char set16[] = "0123456789ABCDEF0123456789abcdef"; static char set10[] = "0123456789"; static void init(void) { char *p; memset(tab.t64, INVAL, sizeof(tab.t64)); memset(tab.t32, INVAL, sizeof(tab.t32)); memset(tab.t16, INVAL, sizeof(tab.t16)); memset(tab.t10, INVAL, sizeof(tab.t10)); for(p = set64; *p; p++) tab.t64[(uchar)*p] = p-set64; for(p = set32; *p; p++) tab.t32[(uchar)*p] = p-set32; for(p = set16; *p; p++) tab.t16[(uchar)*p] = (p-set16)%16; for(p = set10; *p; p++) tab.t10[(uchar)*p] = (p-set10); tab.inited = 1; } static char* from16(char *a, mpint *b) { char *p, *next; int i; mpdigit x; b->top = 0; for(p = a; *p; p++) if(tab.t16[(uchar)*p] == INVAL) break; mpbits(b, (p-a)*4); b->top = 0; next = p; while(p > a){ x = 0; for(i = 0; i < Dbits; i += 4){ if(p <= a) break; x |= tab.t16[(uchar)*--p]<p[b->top++] = x; } return next; } static ulong mppow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; static char* from10(char *a, mpint *b) { ulong x, y; mpint *pow, *r; int i; pow = mpnew(0); r = mpnew(0); b->top = 0; for(;;){ // do a billion at a time in native arithmetic x = 0; for(i = 0; i < 9; i++){ y = tab.t10[(uchar)*a]; if(y == INVAL) break; a++; x *= 10; x += y; } if(i == 0) break; // accumulate into mpint uitomp(mppow10[i], pow); uitomp(x, r); mpmul(b, pow, b); mpadd(b, r, b); if(i != 9) break; } mpfree(pow); mpfree(r); return a; } static char* from64(char *a, mpint *b) { char *buf = a; uchar *p; int n, m; for(; tab.t64[(uchar)*a] != INVAL; a++) ; n = a-buf; mpbits(b, n*6); p = malloc(n); if(p == nil) return a; m = dec64(p, n, buf, n); betomp(p, m, b); free(p); return a; } static char* from32(char *a, mpint *b) { char *buf = a; uchar *p; int n, m; for(; tab.t64[(uchar)*a] != INVAL; a++) ; n = a-buf; mpbits(b, n*5); p = malloc(n); if(p == nil) return a; m = dec32(p, n, buf, n); betomp(p, m, b); free(p); return a; } mpint* strtomp(char *a, char **pp, int base, mpint *b) { int sign; char *e; if(b == nil) b = mpnew(0); if(tab.inited == 0) init(); while(*a==' ' || *a=='\t') a++; sign = 1; for(;; a++){ switch(*a){ case '-': sign *= -1; continue; } break; } switch(base){ case 10: e = from10(a, b); break; default: case 16: e = from16(a, b); break; case 32: e = from32(a, b); break; case 64: e = from64(a, b); break; } // if no characters parsed, there wasn't a number to convert if(e == a) return nil; mpnorm(b); b->sign = sign; if(pp != nil) *pp = e; return b; } drawterm-20170818/libsec/000077500000000000000000000000001314554504700150645ustar00rootroot00000000000000drawterm-20170818/libsec/Makefile000066400000000000000000000014031314554504700165220ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=libsec.a OFILES=\ aes.$O\ blowfish.$O\ decodepem.$O\ des.$O\ des3CBC.$O\ des3ECB.$O\ desCBC.$O\ desECB.$O\ desmodes.$O\ dsaalloc.$O\ dsagen.$O\ dsaprimes.$O\ dsaprivtopub.$O\ dsasign.$O\ dsaverify.$O\ egalloc.$O\ egdecrypt.$O\ egencrypt.$O\ eggen.$O\ egprivtopub.$O\ egsign.$O\ egverify.$O\ fastrand.$O\ genprime.$O\ genrandom.$O\ gensafeprime.$O\ genstrongprime.$O\ hmac.$O\ md4.$O\ md5.$O\ md5pickle.$O\ nfastrand.$O\ prng.$O\ probably_prime.$O\ rc4.$O\ rsaalloc.$O\ rsadecrypt.$O\ rsaencrypt.$O\ rsafill.$O\ rsagen.$O\ rsaprivtopub.$O\ sha1.$O\ sha1pickle.$O\ smallprimes.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/libsec/aes.c000066400000000000000000001752211314554504700160100ustar00rootroot00000000000000/* * this code is derived from the following source, * and modified to fit into the plan 9 libsec interface. * most of the changes are confined to the top section, * with the exception of converting Te4 and Td4 into u8 rather than u32 arrays. * * rijndael-alg-fst.c * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include typedef uchar u8; typedef u32int u32; #define FULL_UNROLL static const u32 Td0[256]; static const u32 Td1[256]; static const u32 Td2[256]; static const u32 Td3[256]; static const u8 Te4[256]; static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); #ifdef NOT static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); #endif static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); static void rijndaelEncrypt(const u32int rk[], int Nr, const uchar pt[16], uchar ct[16]); static void rijndaelDecrypt(const u32int rk[], int Nr, const uchar ct[16], uchar pt[16]); void setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec) { memset(s, 0, sizeof(*s)); if(keybytes > AESmaxkey) keybytes = AESmaxkey; memmove(s->key, key, keybytes); s->keybytes = keybytes; s->rounds = rijndaelKeySetup(s->ekey, s->dkey, s->key, keybytes * 8); if(ivec != nil) memmove(s->ivec, ivec, AESbsize); if(keybytes==16 || keybytes==24 || keybytes==32) s->setup = 0xcafebabe; // else rijndaelKeySetup was invalid } // Define by analogy with desCBCencrypt; AES modes are not standardized yet. // Because of the way that non-multiple-of-16 buffers are handled, // the decryptor must be fed buffers of the same size as the encryptor. void aesCBCencrypt(uchar *p, int len, AESstate *s) { uchar *p2, *ip, *eip; uchar q[AESbsize]; for(; len >= AESbsize; len -= AESbsize){ p2 = p; ip = s->ivec; for(eip = ip+AESbsize; ip < eip; ) *p2++ ^= *ip++; rijndaelEncrypt(s->ekey, s->rounds, p, q); memmove(s->ivec, q, AESbsize); memmove(p, q, AESbsize); p += AESbsize; } if(len > 0){ ip = s->ivec; rijndaelEncrypt(s->ekey, s->rounds, ip, q); memmove(s->ivec, q, AESbsize); for(eip = ip+len; ip < eip; ) *p++ ^= *ip++; } } void aesCBCdecrypt(uchar *p, int len, AESstate *s) { uchar *ip, *eip, *tp; uchar tmp[AESbsize], q[AESbsize]; for(; len >= AESbsize; len -= AESbsize){ memmove(tmp, p, AESbsize); rijndaelDecrypt(s->dkey, s->rounds, p, q); memmove(p, q, AESbsize); tp = tmp; ip = s->ivec; for(eip = ip+AESbsize; ip < eip; ){ *p++ ^= *ip; *ip++ = *tp++; } } if(len > 0){ ip = s->ivec; rijndaelEncrypt(s->ekey, s->rounds, ip, q); memmove(s->ivec, q, AESbsize); for(eip = ip+len; ip < eip; ) *p++ ^= *ip++; } } /* * this function has been changed for plan 9. * Expand the cipher key into the encryption and decryption key schedules. * * @return the number of rounds for the given cipher key size. */ static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int Nr, i; /* expand the cipher key: */ Nr = rijndaelKeySetupEnc(erk, cipherKey, keyBits); /* * invert the order of the round keys and * apply the inverse MixColumn transform to all round keys but the first and the last */ drk[0 ] = erk[4*Nr ]; drk[1 ] = erk[4*Nr + 1]; drk[2 ] = erk[4*Nr + 2]; drk[3 ] = erk[4*Nr + 3]; drk[4*Nr ] = erk[0 ]; drk[4*Nr + 1] = erk[1 ]; drk[4*Nr + 2] = erk[2 ]; drk[4*Nr + 3] = erk[3 ]; erk += 4 * Nr; for (i = 1; i < Nr; i++) { drk += 4; erk -= 4; drk[0] = Td0[Te4[(erk[0] >> 24) ]] ^ Td1[Te4[(erk[0] >> 16) & 0xff]] ^ Td2[Te4[(erk[0] >> 8) & 0xff]] ^ Td3[Te4[(erk[0] ) & 0xff]]; drk[1] = Td0[Te4[(erk[1] >> 24) ]] ^ Td1[Te4[(erk[1] >> 16) & 0xff]] ^ Td2[Te4[(erk[1] >> 8) & 0xff]] ^ Td3[Te4[(erk[1] ) & 0xff]]; drk[2] = Td0[Te4[(erk[2] >> 24) ]] ^ Td1[Te4[(erk[2] >> 16) & 0xff]] ^ Td2[Te4[(erk[2] >> 8) & 0xff]] ^ Td3[Te4[(erk[2] ) & 0xff]]; drk[3] = Td0[Te4[(erk[3] >> 24) ]] ^ Td1[Te4[(erk[3] >> 16) & 0xff]] ^ Td2[Te4[(erk[3] >> 8) & 0xff]] ^ Td3[Te4[(erk[3] ) & 0xff]]; } return Nr; } /* Te0[x] = S [x].[02, 01, 01, 03]; Te1[x] = S [x].[03, 02, 01, 01]; Te2[x] = S [x].[01, 03, 02, 01]; Te3[x] = S [x].[01, 01, 03, 02]; Te4[x] = S [x] Td0[x] = Si[x].[0e, 09, 0d, 0b]; Td1[x] = Si[x].[0b, 0e, 09, 0d]; Td2[x] = Si[x].[0d, 0b, 0e, 09]; Td3[x] = Si[x].[09, 0d, 0b, 0e]; Td4[x] = Si[x] */ static const u32 Te0[256] = { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, }; static const u32 Te1[256] = { 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, }; static const u32 Te2[256] = { 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, }; static const u32 Te3[256] = { 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, }; static const u8 Te4[256] = { 0x63U, 0x7cU, 0x77U, 0x7bU, 0xf2U, 0x6bU, 0x6fU, 0xc5U, 0x30U, 0x01U, 0x67U, 0x2bU, 0xfeU, 0xd7U, 0xabU, 0x76U, 0xcaU, 0x82U, 0xc9U, 0x7dU, 0xfaU, 0x59U, 0x47U, 0xf0U, 0xadU, 0xd4U, 0xa2U, 0xafU, 0x9cU, 0xa4U, 0x72U, 0xc0U, 0xb7U, 0xfdU, 0x93U, 0x26U, 0x36U, 0x3fU, 0xf7U, 0xccU, 0x34U, 0xa5U, 0xe5U, 0xf1U, 0x71U, 0xd8U, 0x31U, 0x15U, 0x04U, 0xc7U, 0x23U, 0xc3U, 0x18U, 0x96U, 0x05U, 0x9aU, 0x07U, 0x12U, 0x80U, 0xe2U, 0xebU, 0x27U, 0xb2U, 0x75U, 0x09U, 0x83U, 0x2cU, 0x1aU, 0x1bU, 0x6eU, 0x5aU, 0xa0U, 0x52U, 0x3bU, 0xd6U, 0xb3U, 0x29U, 0xe3U, 0x2fU, 0x84U, 0x53U, 0xd1U, 0x00U, 0xedU, 0x20U, 0xfcU, 0xb1U, 0x5bU, 0x6aU, 0xcbU, 0xbeU, 0x39U, 0x4aU, 0x4cU, 0x58U, 0xcfU, 0xd0U, 0xefU, 0xaaU, 0xfbU, 0x43U, 0x4dU, 0x33U, 0x85U, 0x45U, 0xf9U, 0x02U, 0x7fU, 0x50U, 0x3cU, 0x9fU, 0xa8U, 0x51U, 0xa3U, 0x40U, 0x8fU, 0x92U, 0x9dU, 0x38U, 0xf5U, 0xbcU, 0xb6U, 0xdaU, 0x21U, 0x10U, 0xffU, 0xf3U, 0xd2U, 0xcdU, 0x0cU, 0x13U, 0xecU, 0x5fU, 0x97U, 0x44U, 0x17U, 0xc4U, 0xa7U, 0x7eU, 0x3dU, 0x64U, 0x5dU, 0x19U, 0x73U, 0x60U, 0x81U, 0x4fU, 0xdcU, 0x22U, 0x2aU, 0x90U, 0x88U, 0x46U, 0xeeU, 0xb8U, 0x14U, 0xdeU, 0x5eU, 0x0bU, 0xdbU, 0xe0U, 0x32U, 0x3aU, 0x0aU, 0x49U, 0x06U, 0x24U, 0x5cU, 0xc2U, 0xd3U, 0xacU, 0x62U, 0x91U, 0x95U, 0xe4U, 0x79U, 0xe7U, 0xc8U, 0x37U, 0x6dU, 0x8dU, 0xd5U, 0x4eU, 0xa9U, 0x6cU, 0x56U, 0xf4U, 0xeaU, 0x65U, 0x7aU, 0xaeU, 0x08U, 0xbaU, 0x78U, 0x25U, 0x2eU, 0x1cU, 0xa6U, 0xb4U, 0xc6U, 0xe8U, 0xddU, 0x74U, 0x1fU, 0x4bU, 0xbdU, 0x8bU, 0x8aU, 0x70U, 0x3eU, 0xb5U, 0x66U, 0x48U, 0x03U, 0xf6U, 0x0eU, 0x61U, 0x35U, 0x57U, 0xb9U, 0x86U, 0xc1U, 0x1dU, 0x9eU, 0xe1U, 0xf8U, 0x98U, 0x11U, 0x69U, 0xd9U, 0x8eU, 0x94U, 0x9bU, 0x1eU, 0x87U, 0xe9U, 0xceU, 0x55U, 0x28U, 0xdfU, 0x8cU, 0xa1U, 0x89U, 0x0dU, 0xbfU, 0xe6U, 0x42U, 0x68U, 0x41U, 0x99U, 0x2dU, 0x0fU, 0xb0U, 0x54U, 0xbbU, 0x16U, }; static const u32 Td0[256] = { 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, }; static const u32 Td1[256] = { 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, }; static const u32 Td2[256] = { 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, }; static const u32 Td3[256] = { 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, }; static const u8 Td4[256] = { 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, }; static const u32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; #define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) #ifdef _MSC_VER #define GETU32(p) SWAP(*((u32 *)(p))) #define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } #else #define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) #define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } #endif /** * Expand the cipher key into the encryption key schedule. * * @return the number of rounds for the given cipher key size. */ static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int i = 0; u32 temp; rk[0] = GETU32(cipherKey ); rk[1] = GETU32(cipherKey + 4); rk[2] = GETU32(cipherKey + 8); rk[3] = GETU32(cipherKey + 12); if (keyBits == 128) { for (;;) { temp = rk[3]; rk[4] = rk[0] ^ (Te4[(temp >> 16) & 0xff] << 24) ^ (Te4[(temp >> 8) & 0xff] << 16) ^ (Te4[(temp ) & 0xff] << 8) ^ (Te4[(temp >> 24) ] ) ^ rcon[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; rk[7] = rk[3] ^ rk[6]; if (++i == 10) { return 10; } rk += 4; } } rk[4] = GETU32(cipherKey + 16); rk[5] = GETU32(cipherKey + 20); if (keyBits == 192) { for (;;) { temp = rk[ 5]; rk[ 6] = rk[ 0] ^ (Te4[(temp >> 16) & 0xff] << 24) ^ (Te4[(temp >> 8) & 0xff] << 16) ^ (Te4[(temp ) & 0xff] << 8) ^ (Te4[(temp >> 24) ] ) ^ rcon[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; rk[ 9] = rk[ 3] ^ rk[ 8]; if (++i == 8) { return 12; } rk[10] = rk[ 4] ^ rk[ 9]; rk[11] = rk[ 5] ^ rk[10]; rk += 6; } } rk[6] = GETU32(cipherKey + 24); rk[7] = GETU32(cipherKey + 28); if (keyBits == 256) { for (;;) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ (Te4[(temp >> 16) & 0xff] << 24) ^ (Te4[(temp >> 8) & 0xff] << 16) ^ (Te4[(temp ) & 0xff] << 8) ^ (Te4[(temp >> 24) ] ) ^ rcon[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; rk[11] = rk[ 3] ^ rk[10]; if (++i == 7) { return 14; } temp = rk[11]; rk[12] = rk[ 4] ^ (Te4[(temp >> 24) ] << 24) ^ (Te4[(temp >> 16) & 0xff] << 16) ^ (Te4[(temp >> 8) & 0xff] << 8) ^ (Te4[(temp ) & 0xff] ); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; rk += 8; } } return 0; } /** * Expand the cipher key into the decryption key schedule. * * @return the number of rounds for the given cipher key size. */ #ifdef NOTUSED static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int Nr, i, j; u32 temp; /* expand the cipher key: */ Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); /* invert the order of the round keys: */ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; } /* apply the inverse MixColumn transform to all round keys but the first and the last: */ for (i = 1; i < Nr; i++) { rk += 4; rk[0] = Td0[Te4[(rk[0] >> 24) ]] ^ Td1[Te4[(rk[0] >> 16) & 0xff]] ^ Td2[Te4[(rk[0] >> 8) & 0xff]] ^ Td3[Te4[(rk[0] ) & 0xff]]; rk[1] = Td0[Te4[(rk[1] >> 24) ]] ^ Td1[Te4[(rk[1] >> 16) & 0xff]] ^ Td2[Te4[(rk[1] >> 8) & 0xff]] ^ Td3[Te4[(rk[1] ) & 0xff]]; rk[2] = Td0[Te4[(rk[2] >> 24) ]] ^ Td1[Te4[(rk[2] >> 16) & 0xff]] ^ Td2[Te4[(rk[2] >> 8) & 0xff]] ^ Td3[Te4[(rk[2] ) & 0xff]]; rk[3] = Td0[Te4[(rk[3] >> 24) ]] ^ Td1[Te4[(rk[3] >> 16) & 0xff]] ^ Td2[Te4[(rk[3] >> 8) & 0xff]] ^ Td3[Te4[(rk[3] ) & 0xff]]; } return Nr; } #endif static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(pt ) ^ rk[0]; s1 = GETU32(pt + 4) ^ rk[1]; s2 = GETU32(pt + 8) ^ rk[2]; s3 = GETU32(pt + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; /* round 2: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; /* round 3: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; /* round 4: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; /* round 5: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; /* round 6: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; /* round 7: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; /* round 8: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; /* round 9: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; /* round 11: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; /* round 13: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Te0[(s0 >> 24) ] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[(s3 ) & 0xff] ^ rk[4]; t1 = Te0[(s1 >> 24) ] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[(s0 ) & 0xff] ^ rk[5]; t2 = Te0[(s2 >> 24) ] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[(s1 ) & 0xff] ^ rk[6]; t3 = Te0[(s3 >> 24) ] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2 ) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Te0[(t0 >> 24) ] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[(t3 ) & 0xff] ^ rk[0]; s1 = Te0[(t1 >> 24) ] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[(t0 ) & 0xff] ^ rk[1]; s2 = Te0[(t2 >> 24) ] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[(t1 ) & 0xff] ^ rk[2]; s3 = Te0[(t3 >> 24) ] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[(t2 ) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Te4[(t0 >> 24) ] << 24) ^ (Te4[(t1 >> 16) & 0xff] << 16) ^ (Te4[(t2 >> 8) & 0xff] << 8) ^ (Te4[(t3 ) & 0xff] ) ^ rk[0]; PUTU32(ct , s0); s1 = (Te4[(t1 >> 24) ] << 24) ^ (Te4[(t2 >> 16) & 0xff] << 16) ^ (Te4[(t3 >> 8) & 0xff] << 8) ^ (Te4[(t0 ) & 0xff] ) ^ rk[1]; PUTU32(ct + 4, s1); s2 = (Te4[(t2 >> 24) ] << 24) ^ (Te4[(t3 >> 16) & 0xff] << 16) ^ (Te4[(t0 >> 8) & 0xff] << 8) ^ (Te4[(t1 ) & 0xff] ) ^ rk[2]; PUTU32(ct + 8, s2); s3 = (Te4[(t3 >> 24) ] << 24) ^ (Te4[(t0 >> 16) & 0xff] << 16) ^ (Te4[(t1 >> 8) & 0xff] << 8) ^ (Te4[(t2 ) & 0xff] ) ^ rk[3]; PUTU32(ct + 12, s3); } static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(ct ) ^ rk[0]; s1 = GETU32(ct + 4) ^ rk[1]; s2 = GETU32(ct + 8) ^ rk[2]; s3 = GETU32(ct + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; /* round 2: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; /* round 3: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; /* round 4: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; /* round 5: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; /* round 6: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; /* round 7: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; /* round 8: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; /* round 9: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; /* round 11: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; /* round 13: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Td0[(s0 >> 24) ] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[(s1 ) & 0xff] ^ rk[4]; t1 = Td0[(s1 >> 24) ] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[(s2 ) & 0xff] ^ rk[5]; t2 = Td0[(s2 >> 24) ] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[(s3 ) & 0xff] ^ rk[6]; t3 = Td0[(s3 >> 24) ] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[(s0 ) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Td0[(t0 >> 24) ] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[(t1 ) & 0xff] ^ rk[0]; s1 = Td0[(t1 >> 24) ] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[(t2 ) & 0xff] ^ rk[1]; s2 = Td0[(t2 >> 24) ] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[(t3 ) & 0xff] ^ rk[2]; s3 = Td0[(t3 >> 24) ] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[(t0 ) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Td4[(t0 >> 24) ] << 24) ^ (Td4[(t3 >> 16) & 0xff] << 16) ^ (Td4[(t2 >> 8) & 0xff] << 8) ^ (Td4[(t1 ) & 0xff] ) ^ rk[0]; PUTU32(pt , s0); s1 = (Td4[(t1 >> 24) ] << 24) ^ (Td4[(t0 >> 16) & 0xff] << 16) ^ (Td4[(t3 >> 8) & 0xff] << 8) ^ (Td4[(t2 ) & 0xff] ) ^ rk[1]; PUTU32(pt + 4, s1); s2 = (Td4[(t2 >> 24) ] << 24) ^ (Td4[(t1 >> 16) & 0xff] << 16) ^ (Td4[(t0 >> 8) & 0xff] << 8) ^ (Td4[(t3 ) & 0xff] ) ^ rk[2]; PUTU32(pt + 8, s2); s3 = (Td4[(t3 >> 24) ] << 24) ^ (Td4[(t2 >> 16) & 0xff] << 16) ^ (Td4[(t1 >> 8) & 0xff] << 8) ^ (Td4[(t0 ) & 0xff] ) ^ rk[3]; PUTU32(pt + 12, s3); } #ifdef INTERMEDIATE_VALUE_KAT static void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) { int r; u32 s0, s1, s2, s3, t0, t1, t2, t3; /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(block ) ^ rk[0]; s1 = GETU32(block + 4) ^ rk[1]; s2 = GETU32(block + 8) ^ rk[2]; s3 = GETU32(block + 12) ^ rk[3]; rk += 4; /* * Nr - 1 full rounds: */ for (r = (rounds < Nr ? rounds : Nr - 1); r > 0; r--) { t0 = Te0[(s0 >> 24) ] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[(s3 ) & 0xff] ^ rk[0]; t1 = Te0[(s1 >> 24) ] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[(s0 ) & 0xff] ^ rk[1]; t2 = Te0[(s2 >> 24) ] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[(s1 ) & 0xff] ^ rk[2]; t3 = Te0[(s3 >> 24) ] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2 ) & 0xff] ^ rk[3]; s0 = t0; s1 = t1; s2 = t2; s3 = t3; rk += 4; } /* * apply last round and * map cipher state to byte array block: */ if (rounds == Nr) { t0 = (Te4[(s0 >> 24) ] << 24) ^ (Te4[(s1 >> 16) & 0xff] << 16) ^ (Te4[(s2 >> 8) & 0xff] << 8) ^ (Te4[(s3 ) & 0xff] ) ^ rk[0]; t1 = (Te4[(s1 >> 24) ] << 24) ^ (Te4[(s2 >> 16) & 0xff] << 16) ^ (Te4[(s3 >> 8) & 0xff] << 8) ^ (Te4[(s0 ) & 0xff] ) ^ rk[1]; t2 = (Te4[(s2 >> 24) ] << 24) ^ (Te4[(s3 >> 16) & 0xff] << 16) ^ (Te4[(s0 >> 8) & 0xff] << 8) ^ (Te4[(s1 ) & 0xff] ) ^ rk[2]; t3 = (Te4[(s3 >> 24) ] << 24) ^ (Te4[(s0 >> 16) & 0xff] << 16) ^ (Te4[(s1 >> 8) & 0xff] << 8) ^ (Te4[(s2 ) & 0xff] ) ^ rk[3]; s0 = t0; s1 = t1; s2 = t2; s3 = t3; } PUTU32(block , s0); PUTU32(block + 4, s1); PUTU32(block + 8, s2); PUTU32(block + 12, s3); } static void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) { int r; u32 s0, s1, s2, s3, t0, t1, t2, t3; /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(block ) ^ rk[0]; s1 = GETU32(block + 4) ^ rk[1]; s2 = GETU32(block + 8) ^ rk[2]; s3 = GETU32(block + 12) ^ rk[3]; rk += 4; /* * Nr - 1 full rounds: */ for (r = (rounds < Nr ? rounds : Nr) - 1; r > 0; r--) { t0 = Td0[(s0 >> 24) ] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[(s1 ) & 0xff] ^ rk[0]; t1 = Td0[(s1 >> 24) ] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[(s2 ) & 0xff] ^ rk[1]; t2 = Td0[(s2 >> 24) ] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[(s3 ) & 0xff] ^ rk[2]; t3 = Td0[(s3 >> 24) ] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[(s0 ) & 0xff] ^ rk[3]; s0 = t0; s1 = t1; s2 = t2; s3 = t3; rk += 4; } /* * complete the last round and * map cipher state to byte array block: */ t0 = (Td4[(s0 >> 24) ] << 24) ^ (Td4[(s3 >> 16) & 0xff] << 16) ^ (Td4[(s2 >> 8) & 0xff] << 8) ^ (Td4[(s1 ) & 0xff] ); t1 = (Td4[(s1 >> 24) ] << 24) ^ (Td4[(s0 >> 16) & 0xff] << 16) ^ (Td4[(s3 >> 8) & 0xff] << 8) ^ (Td4[(s2 ) & 0xff] ); t2 = (Td4[(s2 >> 24) ] << 24) ^ (Td4[(s1 >> 16) & 0xff] << 16) ^ (Td4[(s0 >> 8) & 0xff] << 8) ^ (Td4[(s3 ) & 0xff] ); t3 = (Td4[(s3 >> 24) ] << 24) ^ (Td4[(s2 >> 16) & 0xff] << 16) ^ (Td4[(s1 >> 8) & 0xff] << 8) ^ (Td4[(s0 ) & 0xff] ); if (rounds == Nr) { t0 ^= rk[0]; t1 ^= rk[1]; t2 ^= rk[2]; t3 ^= rk[3]; } PUTU32(block , t0); PUTU32(block + 4, t1); PUTU32(block + 8, t2); PUTU32(block + 12, t3); } #endif /* INTERMEDIATE_VALUE_KAT */ drawterm-20170818/libsec/blowfish.c000066400000000000000000000463341314554504700170570ustar00rootroot00000000000000#include "os.h" #include #include // Blowfish block cipher. See: // Lecture Notes in Computer Science 809 // Fast Software Encryption // Cambridge Security Workshop, Cambridge, England (1993) static u32int sbox[1024]; static u32int pbox[BFrounds+2]; static void bfencrypt(u32int *, BFstate *); static void bfdecrypt(u32int *, BFstate *); void setupBFstate(BFstate *s, uchar key[], int keybytes, uchar *ivec) { int i, j; u32int n, buf[2]; memset(s, 0, sizeof(*s)); memset(buf, 0, sizeof buf); if (keybytes > sizeof(s->key)) keybytes = sizeof(s->key); memmove(s->key, key, keybytes); if (ivec != nil) memmove(s->ivec, ivec, sizeof(s->ivec)); else memset(s->ivec, 0, sizeof(s->ivec)); memmove(s->pbox, pbox, sizeof(pbox)); memmove(s->sbox, sbox, sizeof(sbox)); if (keybytes > 4*(BFrounds + 2)) keybytes = 4*(BFrounds + 2); for(i=j=0; i < BFrounds+2; i++) { n = key[j]; j = (j+1) % keybytes; n <<= 8; n |= key[j]; j = (j+1) % keybytes; n <<= 8; n |= key[j]; j = (j+1) % keybytes; n <<= 8; n |= key[j]; j = (j+1) % keybytes; s->pbox[i] ^= n; } for(i=0; i < BFrounds+2; i += 2) { bfencrypt(buf, s); s->pbox[i] = buf[0]; s->pbox[i+1] = buf[1]; } for(i=0; i < 1024; i += 2) { bfencrypt(buf, s); s->sbox[i] = buf[0]; s->sbox[i+1] = buf[1]; } s->setup = 0xcafebabe; } void bfCBCencrypt(uchar *buf, int n, BFstate *s) { int i; uchar *p; u32int bo[2], bi[2], b; assert((n & 7) == 0); bo[0] = s->ivec[0] | ((u32int) s->ivec[1]<<8) | ((u32int)s->ivec[2]<<16) | ((u32int)s->ivec[3]<<24); bo[1] = s->ivec[4] | ((u32int) s->ivec[5]<<8) | ((u32int)s->ivec[6]<<16) | ((u32int)s->ivec[7]<<24); for(i=0; i < n; i += 8, buf += 8) { bi[0] = buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24); bi[1] = buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24); bi[0] ^= bo[0]; bi[1] ^= bo[1]; bfencrypt(bi, s); bo[0] = bi[0]; bo[1] = bi[1]; p = buf; b = bo[0]; *p++ = b; b >>= 8; *p++ = b; b >>= 8; *p++ = b; b >>= 8; *p++ = b; b = bo[1]; *p++ = b; b >>= 8; *p++ = b; b >>= 8; *p++ = b; b >>= 8; *p = b; } s->ivec[7] = bo[1] >> 24; s->ivec[6] = bo[1] >> 16; s->ivec[5] = bo[1] >> 8; s->ivec[4] = bo[1]; s->ivec[3] = bo[0] >> 24; s->ivec[2] = bo[0] >> 16; s->ivec[1] = bo[0] >> 8; s->ivec[0] = bo[0]; return; } void bfCBCdecrypt(uchar *buf, int n, BFstate *s) { int i; uchar *p; u32int b, bo[2], bi[2], xr[2]; assert((n & 7) == 0); bo[0] = s->ivec[0] | ((u32int) s->ivec[1]<<8) | ((u32int)s->ivec[2]<<16) | ((u32int)s->ivec[3]<<24); bo[1] = s->ivec[4] | ((u32int) s->ivec[5]<<8) | ((u32int)s->ivec[6]<<16) | ((u32int)s->ivec[7]<<24); for(i=0; i < n; i += 8, buf += 8) { bi[0] = buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24); bi[1] = buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24); xr[0] = bi[0]; xr[1] = bi[1]; bfdecrypt(bi, s); bo[0] ^= bi[0]; bo[1] ^= bi[1]; p = buf; b = bo[0]; *p++ = b; b >>= 8; *p++ = b; b >>= 8; *p++ = b; b >>= 8; *p++ = b; b = bo[1]; *p++ = b; b >>= 8; *p++ = b; b >>= 8; *p++ = b; b >>= 8; *p = b; bo[0] = xr[0]; bo[1] = xr[1]; } s->ivec[7] = bo[1] >> 24; s->ivec[6] = bo[1] >> 16; s->ivec[5] = bo[1] >> 8; s->ivec[4] = bo[1]; s->ivec[3] = bo[0] >> 24; s->ivec[2] = bo[0] >> 16; s->ivec[1] = bo[0] >> 8; s->ivec[0] = bo[0]; return; } void bfECBencrypt(uchar *buf, int n, BFstate *s) { int i; u32int b[2]; for(i=0; i < n; i += 8, buf += 8) { b[0] = buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24); b[1] = buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24); bfencrypt(b, s); buf[7] = b[1] >> 24; buf[6] = b[1] >> 16; buf[5] = b[1] >> 8; buf[4] = b[1]; buf[3] = b[0] >> 24; buf[2] = b[0] >> 16; buf[1] = b[0] >> 8; buf[0] = b[0]; } return; } void bfECBdecrypt(uchar *buf, int n, BFstate *s) { int i; u32int b[2]; for(i=0; i < n; i += 8, buf += 8) { b[0] = buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24); b[1] = buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24); bfdecrypt(b, s); buf[7] = b[1] >> 24; buf[6] = b[1] >> 16; buf[5] = b[1] >> 8; buf[4] = b[1]; buf[3] = b[0] >> 24; buf[2] = b[0] >> 16; buf[1] = b[0] >> 8; buf[0] = b[0]; } return; } static void bfencrypt(u32int *b, BFstate *s) { int i; u32int l, r; u32int *pb, *sb; l = b[0]; r = b[1]; pb = s->pbox; sb = s->sbox; l ^= pb[0]; for(i=1; i<16; i += 2) { r ^= pb[i]; r ^= ( (sb[ (uchar) (l>>24)] + sb[256 + ((uchar) (l>>16))]) ^ sb[512 + ((uchar) (l>>8))]) + sb[768 +((uchar) l)]; l ^= pb[i+1]; l ^= ( (sb[ (uchar) (r>>24)] + sb[256 + ((uchar) (r>>16))]) ^ sb[512 + ((uchar) (r>>8))]) + sb[768 +((uchar) r)]; } r ^= pb[BFrounds+1]; /* sic */ b[0] = r; b[1] = l; return; } static void bfdecrypt(u32int *b, BFstate *s) { int i; u32int l, r; u32int *pb, *sb; l = b[0]; r = b[1]; pb = s->pbox; sb = s->sbox; l ^= pb[BFrounds+1]; for(i=16; i > 0; i -= 2) { r ^= pb[i]; r ^= ( (sb[ (uchar) (l>>24)] + sb[256 + ((uchar) (l>>16))]) ^ sb[512 + ((uchar) (l>>8))]) + sb[768 +((uchar) l)]; l ^= pb[i-1]; l ^= ( (sb[ (uchar) (r>>24)] + sb[256 + ((uchar) (r>>16))]) ^ sb[512 + ((uchar) (r>>8))]) + sb[768 +((uchar) r)]; } r ^= pb[0]; /* sic */ b[0] = r; b[1] = l; return; } static u32int pbox[BFrounds+2] = { 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b }; static u32int sbox[1024] = { 0xd1310ba6L, 0x98dfb5acL, 0x2ffd72dbL, 0xd01adfb7L, 0xb8e1afedL, 0x6a267e96L, 0xba7c9045L, 0xf12c7f99L, 0x24a19947L, 0xb3916cf7L, 0x0801f2e2L, 0x858efc16L, 0x636920d8L, 0x71574e69L, 0xa458fea3L, 0xf4933d7eL, 0x0d95748fL, 0x728eb658L, 0x718bcd58L, 0x82154aeeL, 0x7b54a41dL, 0xc25a59b5L, 0x9c30d539L, 0x2af26013L, 0xc5d1b023L, 0x286085f0L, 0xca417918L, 0xb8db38efL, 0x8e79dcb0L, 0x603a180eL, 0x6c9e0e8bL, 0xb01e8a3eL, 0xd71577c1L, 0xbd314b27L, 0x78af2fdaL, 0x55605c60L, 0xe65525f3L, 0xaa55ab94L, 0x57489862L, 0x63e81440L, 0x55ca396aL, 0x2aab10b6L, 0xb4cc5c34L, 0x1141e8ceL, 0xa15486afL, 0x7c72e993L, 0xb3ee1411L, 0x636fbc2aL, 0x2ba9c55dL, 0x741831f6L, 0xce5c3e16L, 0x9b87931eL, 0xafd6ba33L, 0x6c24cf5cL, 0x7a325381L, 0x28958677L, 0x3b8f4898L, 0x6b4bb9afL, 0xc4bfe81bL, 0x66282193L, 0x61d809ccL, 0xfb21a991L, 0x487cac60L, 0x5dec8032L, 0xef845d5dL, 0xe98575b1L, 0xdc262302L, 0xeb651b88L, 0x23893e81L, 0xd396acc5L, 0x0f6d6ff3L, 0x83f44239L, 0x2e0b4482L, 0xa4842004L, 0x69c8f04aL, 0x9e1f9b5eL, 0x21c66842L, 0xf6e96c9aL, 0x670c9c61L, 0xabd388f0L, 0x6a51a0d2L, 0xd8542f68L, 0x960fa728L, 0xab5133a3L, 0x6eef0b6cL, 0x137a3be4L, 0xba3bf050L, 0x7efb2a98L, 0xa1f1651dL, 0x39af0176L, 0x66ca593eL, 0x82430e88L, 0x8cee8619L, 0x456f9fb4L, 0x7d84a5c3L, 0x3b8b5ebeL, 0xe06f75d8L, 0x85c12073L, 0x401a449fL, 0x56c16aa6L, 0x4ed3aa62L, 0x363f7706L, 0x1bfedf72L, 0x429b023dL, 0x37d0d724L, 0xd00a1248L, 0xdb0fead3L, 0x49f1c09bL, 0x075372c9L, 0x80991b7bL, 0x25d479d8L, 0xf6e8def7L, 0xe3fe501aL, 0xb6794c3bL, 0x976ce0bdL, 0x04c006baL, 0xc1a94fb6L, 0x409f60c4L, 0x5e5c9ec2L, 0x196a2463L, 0x68fb6fafL, 0x3e6c53b5L, 0x1339b2ebL, 0x3b52ec6fL, 0x6dfc511fL, 0x9b30952cL, 0xcc814544L, 0xaf5ebd09L, 0xbee3d004L, 0xde334afdL, 0x660f2807L, 0x192e4bb3L, 0xc0cba857L, 0x45c8740fL, 0xd20b5f39L, 0xb9d3fbdbL, 0x5579c0bdL, 0x1a60320aL, 0xd6a100c6L, 0x402c7279L, 0x679f25feL, 0xfb1fa3ccL, 0x8ea5e9f8L, 0xdb3222f8L, 0x3c7516dfL, 0xfd616b15L, 0x2f501ec8L, 0xad0552abL, 0x323db5faL, 0xfd238760L, 0x53317b48L, 0x3e00df82L, 0x9e5c57bbL, 0xca6f8ca0L, 0x1a87562eL, 0xdf1769dbL, 0xd542a8f6L, 0x287effc3L, 0xac6732c6L, 0x8c4f5573L, 0x695b27b0L, 0xbbca58c8L, 0xe1ffa35dL, 0xb8f011a0L, 0x10fa3d98L, 0xfd2183b8L, 0x4afcb56cL, 0x2dd1d35bL, 0x9a53e479L, 0xb6f84565L, 0xd28e49bcL, 0x4bfb9790L, 0xe1ddf2daL, 0xa4cb7e33L, 0x62fb1341L, 0xcee4c6e8L, 0xef20cadaL, 0x36774c01L, 0xd07e9efeL, 0x2bf11fb4L, 0x95dbda4dL, 0xae909198L, 0xeaad8e71L, 0x6b93d5a0L, 0xd08ed1d0L, 0xafc725e0L, 0x8e3c5b2fL, 0x8e7594b7L, 0x8ff6e2fbL, 0xf2122b64L, 0x8888b812L, 0x900df01cL, 0x4fad5ea0L, 0x688fc31cL, 0xd1cff191L, 0xb3a8c1adL, 0x2f2f2218L, 0xbe0e1777L, 0xea752dfeL, 0x8b021fa1L, 0xe5a0cc0fL, 0xb56f74e8L, 0x18acf3d6L, 0xce89e299L, 0xb4a84fe0L, 0xfd13e0b7L, 0x7cc43b81L, 0xd2ada8d9L, 0x165fa266L, 0x80957705L, 0x93cc7314L, 0x211a1477L, 0xe6ad2065L, 0x77b5fa86L, 0xc75442f5L, 0xfb9d35cfL, 0xebcdaf0cL, 0x7b3e89a0L, 0xd6411bd3L, 0xae1e7e49L, 0x00250e2dL, 0x2071b35eL, 0x226800bbL, 0x57b8e0afL, 0x2464369bL, 0xf009b91eL, 0x5563911dL, 0x59dfa6aaL, 0x78c14389L, 0xd95a537fL, 0x207d5ba2L, 0x02e5b9c5L, 0x83260376L, 0x6295cfa9L, 0x11c81968L, 0x4e734a41L, 0xb3472dcaL, 0x7b14a94aL, 0x1b510052L, 0x9a532915L, 0xd60f573fL, 0xbc9bc6e4L, 0x2b60a476L, 0x81e67400L, 0x08ba6fb5L, 0x571be91fL, 0xf296ec6bL, 0x2a0dd915L, 0xb6636521L, 0xe7b9f9b6L, 0xff34052eL, 0xc5855664L, 0x53b02d5dL, 0xa99f8fa1L, 0x08ba4799L, 0x6e85076aL, 0x4b7a70e9L, 0xb5b32944L, 0xdb75092eL, 0xc4192623L, 0xad6ea6b0L, 0x49a7df7dL, 0x9cee60b8L, 0x8fedb266L, 0xecaa8c71L, 0x699a17ffL, 0x5664526cL, 0xc2b19ee1L, 0x193602a5L, 0x75094c29L, 0xa0591340L, 0xe4183a3eL, 0x3f54989aL, 0x5b429d65L, 0x6b8fe4d6L, 0x99f73fd6L, 0xa1d29c07L, 0xefe830f5L, 0x4d2d38e6L, 0xf0255dc1L, 0x4cdd2086L, 0x8470eb26L, 0x6382e9c6L, 0x021ecc5eL, 0x09686b3fL, 0x3ebaefc9L, 0x3c971814L, 0x6b6a70a1L, 0x687f3584L, 0x52a0e286L, 0xb79c5305L, 0xaa500737L, 0x3e07841cL, 0x7fdeae5cL, 0x8e7d44ecL, 0x5716f2b8L, 0xb03ada37L, 0xf0500c0dL, 0xf01c1f04L, 0x0200b3ffL, 0xae0cf51aL, 0x3cb574b2L, 0x25837a58L, 0xdc0921bdL, 0xd19113f9L, 0x7ca92ff6L, 0x94324773L, 0x22f54701L, 0x3ae5e581L, 0x37c2dadcL, 0xc8b57634L, 0x9af3dda7L, 0xa9446146L, 0x0fd0030eL, 0xecc8c73eL, 0xa4751e41L, 0xe238cd99L, 0x3bea0e2fL, 0x3280bba1L, 0x183eb331L, 0x4e548b38L, 0x4f6db908L, 0x6f420d03L, 0xf60a04bfL, 0x2cb81290L, 0x24977c79L, 0x5679b072L, 0xbcaf89afL, 0xde9a771fL, 0xd9930810L, 0xb38bae12L, 0xdccf3f2eL, 0x5512721fL, 0x2e6b7124L, 0x501adde6L, 0x9f84cd87L, 0x7a584718L, 0x7408da17L, 0xbc9f9abcL, 0xe94b7d8cL, 0xec7aec3aL, 0xdb851dfaL, 0x63094366L, 0xc464c3d2L, 0xef1c1847L, 0x3215d908L, 0xdd433b37L, 0x24c2ba16L, 0x12a14d43L, 0x2a65c451L, 0x50940002L, 0x133ae4ddL, 0x71dff89eL, 0x10314e55L, 0x81ac77d6L, 0x5f11199bL, 0x043556f1L, 0xd7a3c76bL, 0x3c11183bL, 0x5924a509L, 0xf28fe6edL, 0x97f1fbfaL, 0x9ebabf2cL, 0x1e153c6eL, 0x86e34570L, 0xeae96fb1L, 0x860e5e0aL, 0x5a3e2ab3L, 0x771fe71cL, 0x4e3d06faL, 0x2965dcb9L, 0x99e71d0fL, 0x803e89d6L, 0x5266c825L, 0x2e4cc978L, 0x9c10b36aL, 0xc6150ebaL, 0x94e2ea78L, 0xa5fc3c53L, 0x1e0a2df4L, 0xf2f74ea7L, 0x361d2b3dL, 0x1939260fL, 0x19c27960L, 0x5223a708L, 0xf71312b6L, 0xebadfe6eL, 0xeac31f66L, 0xe3bc4595L, 0xa67bc883L, 0xb17f37d1L, 0x018cff28L, 0xc332ddefL, 0xbe6c5aa5L, 0x65582185L, 0x68ab9802L, 0xeecea50fL, 0xdb2f953bL, 0x2aef7dadL, 0x5b6e2f84L, 0x1521b628L, 0x29076170L, 0xecdd4775L, 0x619f1510L, 0x13cca830L, 0xeb61bd96L, 0x0334fe1eL, 0xaa0363cfL, 0xb5735c90L, 0x4c70a239L, 0xd59e9e0bL, 0xcbaade14L, 0xeecc86bcL, 0x60622ca7L, 0x9cab5cabL, 0xb2f3846eL, 0x648b1eafL, 0x19bdf0caL, 0xa02369b9L, 0x655abb50L, 0x40685a32L, 0x3c2ab4b3L, 0x319ee9d5L, 0xc021b8f7L, 0x9b540b19L, 0x875fa099L, 0x95f7997eL, 0x623d7da8L, 0xf837889aL, 0x97e32d77L, 0x11ed935fL, 0x16681281L, 0x0e358829L, 0xc7e61fd6L, 0x96dedfa1L, 0x7858ba99L, 0x57f584a5L, 0x1b227263L, 0x9b83c3ffL, 0x1ac24696L, 0xcdb30aebL, 0x532e3054L, 0x8fd948e4L, 0x6dbc3128L, 0x58ebf2efL, 0x34c6ffeaL, 0xfe28ed61L, 0xee7c3c73L, 0x5d4a14d9L, 0xe864b7e3L, 0x42105d14L, 0x203e13e0L, 0x45eee2b6L, 0xa3aaabeaL, 0xdb6c4f15L, 0xfacb4fd0L, 0xc742f442L, 0xef6abbb5L, 0x654f3b1dL, 0x41cd2105L, 0xd81e799eL, 0x86854dc7L, 0xe44b476aL, 0x3d816250L, 0xcf62a1f2L, 0x5b8d2646L, 0xfc8883a0L, 0xc1c7b6a3L, 0x7f1524c3L, 0x69cb7492L, 0x47848a0bL, 0x5692b285L, 0x095bbf00L, 0xad19489dL, 0x1462b174L, 0x23820e00L, 0x58428d2aL, 0x0c55f5eaL, 0x1dadf43eL, 0x233f7061L, 0x3372f092L, 0x8d937e41L, 0xd65fecf1L, 0x6c223bdbL, 0x7cde3759L, 0xcbee7460L, 0x4085f2a7L, 0xce77326eL, 0xa6078084L, 0x19f8509eL, 0xe8efd855L, 0x61d99735L, 0xa969a7aaL, 0xc50c06c2L, 0x5a04abfcL, 0x800bcadcL, 0x9e447a2eL, 0xc3453484L, 0xfdd56705L, 0x0e1e9ec9L, 0xdb73dbd3L, 0x105588cdL, 0x675fda79L, 0xe3674340L, 0xc5c43465L, 0x713e38d8L, 0x3d28f89eL, 0xf16dff20L, 0x153e21e7L, 0x8fb03d4aL, 0xe6e39f2bL, 0xdb83adf7L, 0xe93d5a68L, 0x948140f7L, 0xf64c261cL, 0x94692934L, 0x411520f7L, 0x7602d4f7L, 0xbcf46b2eL, 0xd4a20068L, 0xd4082471L, 0x3320f46aL, 0x43b7d4b7L, 0x500061afL, 0x1e39f62eL, 0x97244546L, 0x14214f74L, 0xbf8b8840L, 0x4d95fc1dL, 0x96b591afL, 0x70f4ddd3L, 0x66a02f45L, 0xbfbc09ecL, 0x03bd9785L, 0x7fac6dd0L, 0x31cb8504L, 0x96eb27b3L, 0x55fd3941L, 0xda2547e6L, 0xabca0a9aL, 0x28507825L, 0x530429f4L, 0x0a2c86daL, 0xe9b66dfbL, 0x68dc1462L, 0xd7486900L, 0x680ec0a4L, 0x27a18deeL, 0x4f3ffea2L, 0xe887ad8cL, 0xb58ce006L, 0x7af4d6b6L, 0xaace1e7cL, 0xd3375fecL, 0xce78a399L, 0x406b2a42L, 0x20fe9e35L, 0xd9f385b9L, 0xee39d7abL, 0x3b124e8bL, 0x1dc9faf7L, 0x4b6d1856L, 0x26a36631L, 0xeae397b2L, 0x3a6efa74L, 0xdd5b4332L, 0x6841e7f7L, 0xca7820fbL, 0xfb0af54eL, 0xd8feb397L, 0x454056acL, 0xba489527L, 0x55533a3aL, 0x20838d87L, 0xfe6ba9b7L, 0xd096954bL, 0x55a867bcL, 0xa1159a58L, 0xcca92963L, 0x99e1db33L, 0xa62a4a56L, 0x3f3125f9L, 0x5ef47e1cL, 0x9029317cL, 0xfdf8e802L, 0x04272f70L, 0x80bb155cL, 0x05282ce3L, 0x95c11548L, 0xe4c66d22L, 0x48c1133fL, 0xc70f86dcL, 0x07f9c9eeL, 0x41041f0fL, 0x404779a4L, 0x5d886e17L, 0x325f51ebL, 0xd59bc0d1L, 0xf2bcc18fL, 0x41113564L, 0x257b7834L, 0x602a9c60L, 0xdff8e8a3L, 0x1f636c1bL, 0x0e12b4c2L, 0x02e1329eL, 0xaf664fd1L, 0xcad18115L, 0x6b2395e0L, 0x333e92e1L, 0x3b240b62L, 0xeebeb922L, 0x85b2a20eL, 0xe6ba0d99L, 0xde720c8cL, 0x2da2f728L, 0xd0127845L, 0x95b794fdL, 0x647d0862L, 0xe7ccf5f0L, 0x5449a36fL, 0x877d48faL, 0xc39dfd27L, 0xf33e8d1eL, 0x0a476341L, 0x992eff74L, 0x3a6f6eabL, 0xf4f8fd37L, 0xa812dc60L, 0xa1ebddf8L, 0x991be14cL, 0xdb6e6b0dL, 0xc67b5510L, 0x6d672c37L, 0x2765d43bL, 0xdcd0e804L, 0xf1290dc7L, 0xcc00ffa3L, 0xb5390f92L, 0x690fed0bL, 0x667b9ffbL, 0xcedb7d9cL, 0xa091cf0bL, 0xd9155ea3L, 0xbb132f88L, 0x515bad24L, 0x7b9479bfL, 0x763bd6ebL, 0x37392eb3L, 0xcc115979L, 0x8026e297L, 0xf42e312dL, 0x6842ada7L, 0xc66a2b3bL, 0x12754cccL, 0x782ef11cL, 0x6a124237L, 0xb79251e7L, 0x06a1bbe6L, 0x4bfb6350L, 0x1a6b1018L, 0x11caedfaL, 0x3d25bdd8L, 0xe2e1c3c9L, 0x44421659L, 0x0a121386L, 0xd90cec6eL, 0xd5abea2aL, 0x64af674eL, 0xda86a85fL, 0xbebfe988L, 0x64e4c3feL, 0x9dbc8057L, 0xf0f7c086L, 0x60787bf8L, 0x6003604dL, 0xd1fd8346L, 0xf6381fb0L, 0x7745ae04L, 0xd736fcccL, 0x83426b33L, 0xf01eab71L, 0xb0804187L, 0x3c005e5fL, 0x77a057beL, 0xbde8ae24L, 0x55464299L, 0xbf582e61L, 0x4e58f48fL, 0xf2ddfda2L, 0xf474ef38L, 0x8789bdc2L, 0x5366f9c3L, 0xc8b38e74L, 0xb475f255L, 0x46fcd9b9L, 0x7aeb2661L, 0x8b1ddf84L, 0x846a0e79L, 0x915f95e2L, 0x466e598eL, 0x20b45770L, 0x8cd55591L, 0xc902de4cL, 0xb90bace1L, 0xbb8205d0L, 0x11a86248L, 0x7574a99eL, 0xb77f19b6L, 0xe0a9dc09L, 0x662d09a1L, 0xc4324633L, 0xe85a1f02L, 0x09f0be8cL, 0x4a99a025L, 0x1d6efe10L, 0x1ab93d1dL, 0x0ba5a4dfL, 0xa186f20fL, 0x2868f169L, 0xdcb7da83L, 0x573906feL, 0xa1e2ce9bL, 0x4fcd7f52L, 0x50115e01L, 0xa70683faL, 0xa002b5c4L, 0x0de6d027L, 0x9af88c27L, 0x773f8641L, 0xc3604c06L, 0x61a806b5L, 0xf0177a28L, 0xc0f586e0L, 0x006058aaL, 0x30dc7d62L, 0x11e69ed7L, 0x2338ea63L, 0x53c2dd94L, 0xc2c21634L, 0xbbcbee56L, 0x90bcb6deL, 0xebfc7da1L, 0xce591d76L, 0x6f05e409L, 0x4b7c0188L, 0x39720a3dL, 0x7c927c24L, 0x86e3725fL, 0x724d9db9L, 0x1ac15bb4L, 0xd39eb8fcL, 0xed545578L, 0x08fca5b5L, 0xd83d7cd3L, 0x4dad0fc4L, 0x1e50ef5eL, 0xb161e6f8L, 0xa28514d9L, 0x6c51133cL, 0x6fd5c7e7L, 0x56e14ec4L, 0x362abfceL, 0xddc6c837L, 0xd79a3234L, 0x92638212L, 0x670efa8eL, 0x406000e0L, 0x3a39ce37L, 0xd3faf5cfL, 0xabc27737L, 0x5ac52d1bL, 0x5cb0679eL, 0x4fa33742L, 0xd3822740L, 0x99bc9bbeL, 0xd5118e9dL, 0xbf0f7315L, 0xd62d1c7eL, 0xc700c47bL, 0xb78c1b6bL, 0x21a19045L, 0xb26eb1beL, 0x6a366eb4L, 0x5748ab2fL, 0xbc946e79L, 0xc6a376d2L, 0x6549c2c8L, 0x530ff8eeL, 0x468dde7dL, 0xd5730a1dL, 0x4cd04dc6L, 0x2939bbdbL, 0xa9ba4650L, 0xac9526e8L, 0xbe5ee304L, 0xa1fad5f0L, 0x6a2d519aL, 0x63ef8ce2L, 0x9a86ee22L, 0xc089c2b8L, 0x43242ef6L, 0xa51e03aaL, 0x9cf2d0a4L, 0x83c061baL, 0x9be96a4dL, 0x8fe51550L, 0xba645bd6L, 0x2826a2f9L, 0xa73a3ae1L, 0x4ba99586L, 0xef5562e9L, 0xc72fefd3L, 0xf752f7daL, 0x3f046f69L, 0x77fa0a59L, 0x80e4a915L, 0x87b08601L, 0x9b09e6adL, 0x3b3ee593L, 0xe990fd5aL, 0x9e34d797L, 0x2cf0b7d9L, 0x022b8b51L, 0x96d5ac3aL, 0x017da67dL, 0xd1cf3ed6L, 0x7c7d2d28L, 0x1f9f25cfL, 0xadf2b89bL, 0x5ad6b472L, 0x5a88f54cL, 0xe029ac71L, 0xe019a5e6L, 0x47b0acfdL, 0xed93fa9bL, 0xe8d3c48dL, 0x283b57ccL, 0xf8d56629L, 0x79132e28L, 0x785f0191L, 0xed756055L, 0xf7960e44L, 0xe3d35e8cL, 0x15056dd4L, 0x88f46dbaL, 0x03a16125L, 0x0564f0bdL, 0xc3eb9e15L, 0x3c9057a2L, 0x97271aecL, 0xa93a072aL, 0x1b3f6d9bL, 0x1e6321f5L, 0xf59c66fbL, 0x26dcf319L, 0x7533d928L, 0xb155fdf5L, 0x03563482L, 0x8aba3cbbL, 0x28517711L, 0xc20ad9f8L, 0xabcc5167L, 0xccad925fL, 0x4de81751L, 0x3830dc8eL, 0x379d5862L, 0x9320f991L, 0xea7a90c2L, 0xfb3e7bceL, 0x5121ce64L, 0x774fbe32L, 0xa8b6e37eL, 0xc3293d46L, 0x48de5369L, 0x6413e680L, 0xa2ae0810L, 0xdd6db224L, 0x69852dfdL, 0x09072166L, 0xb39a460aL, 0x6445c0ddL, 0x586cdecfL, 0x1c20c8aeL, 0x5bbef7ddL, 0x1b588d40L, 0xccd2017fL, 0x6bb4e3bbL, 0xdda26a7eL, 0x3a59ff45L, 0x3e350a44L, 0xbcb4cdd5L, 0x72eacea8L, 0xfa6484bbL, 0x8d6612aeL, 0xbf3c6f47L, 0xd29be463L, 0x542f5d9eL, 0xaec2771bL, 0xf64e6370L, 0x740e0d8dL, 0xe75b1357L, 0xf8721671L, 0xaf537d5dL, 0x4040cb08L, 0x4eb4e2ccL, 0x34d2466aL, 0x0115af84L, 0xe1b00428L, 0x95983a1dL, 0x06b89fb4L, 0xce6ea048L, 0x6f3f3b82L, 0x3520ab82L, 0x011a1d4bL, 0x277227f8L, 0x611560b1L, 0xe7933fdcL, 0xbb3a792bL, 0x344525bdL, 0xa08839e1L, 0x51ce794bL, 0x2f32c9b7L, 0xa01fbac9L, 0xe01cc87eL, 0xbcc7d1f6L, 0xcf0111c3L, 0xa1e8aac7L, 0x1a908749L, 0xd44fbd9aL, 0xd0dadecbL, 0xd50ada38L, 0x0339c32aL, 0xc6913667L, 0x8df9317cL, 0xe0b12b4fL, 0xf79e59b7L, 0x43f5bb3aL, 0xf2d519ffL, 0x27d9459cL, 0xbf97222cL, 0x15e6fc2aL, 0x0f91fc71L, 0x9b941525L, 0xfae59361L, 0xceb69cebL, 0xc2a86459L, 0x12baa8d1L, 0xb6c1075eL, 0xe3056a0cL, 0x10d25065L, 0xcb03a442L, 0xe0ec6e0eL, 0x1698db3bL, 0x4c98a0beL, 0x3278e964L, 0x9f1f9532L, 0xe0d392dfL, 0xd3a0342bL, 0x8971f21eL, 0x1b0a7441L, 0x4ba3348cL, 0xc5be7120L, 0xc37632d8L, 0xdf359f8dL, 0x9b992f2eL, 0xe60b6f47L, 0x0fe3f11dL, 0xe54cda54L, 0x1edad891L, 0xce6279cfL, 0xcd3e7e6fL, 0x1618b166L, 0xfd2c1d05L, 0x848fd2c5L, 0xf6fb2299L, 0xf523f357L, 0xa6327623L, 0x93a83531L, 0x56cccd02L, 0xacf08162L, 0x5a75ebb5L, 0x6e163697L, 0x88d273ccL, 0xde966292L, 0x81b949d0L, 0x4c50901bL, 0x71c65614L, 0xe6c6c7bdL, 0x327a140aL, 0x45e1d006L, 0xc3f27b9aL, 0xc9aa53fdL, 0x62a80f00L, 0xbb25bfe2L, 0x35bdd2f6L, 0x71126905L, 0xb2040222L, 0xb6cbcf7cL, 0xcd769c2bL, 0x53113ec0L, 0x1640e3d3L, 0x38abbd60L, 0x2547adf0L, 0xba38209cL, 0xf746ce76L, 0x77afa1c5L, 0x20756060L, 0x85cbfe4eL, 0x8ae88dd8L, 0x7aaaf9b0L, 0x4cf9aa7eL, 0x1948c25cL, 0x02fb8a8cL, 0x01c36ae4L, 0xd6ebe1f9L, 0x90d4f869L, 0xa65cdea0L, 0x3f09252dL, 0xc208e69fL, 0xb74e6132L, 0xce77e25bL, 0x578fdfe3L, 0x3ac372e6L, }; drawterm-20170818/libsec/decodepem.c000066400000000000000000000025331314554504700171600ustar00rootroot00000000000000#include #include #include #include #define STRLEN(s) (sizeof(s)-1) uchar* decodepem(char *s, char *type, int *len) { uchar *d; char *t, *e, *tt; int n; /* * find the correct section of the file, stripping garbage at the beginning and end. * the data is delimited by -----BEGIN -----\n and -----END -----\n */ n = strlen(type); e = strchr(s, '\0'); for(t = s; t != nil && t < e; ){ tt = t; t = strchr(tt, '\n'); if(t != nil) t++; if(strncmp(tt, "-----BEGIN ", STRLEN("-----BEGIN ")) == 0 && strncmp(&tt[STRLEN("-----BEGIN ")], type, n) == 0 && strncmp(&tt[STRLEN("-----BEGIN ")+n], "-----\n", STRLEN("-----\n")) == 0) break; } for(tt = t; tt != nil && tt < e; tt++){ if(strncmp(tt, "-----END ", STRLEN("-----END ")) == 0 && strncmp(&tt[STRLEN("-----END ")], type, n) == 0 && strncmp(&tt[STRLEN("-----END ")+n], "-----\n", STRLEN("-----\n")) == 0) break; tt = strchr(tt, '\n'); if(tt == nil) break; } if(tt == nil || tt == e){ werrstr("incorrect .pem file format: bad header or trailer"); return nil; } n = ((tt - t) * 6 + 7) / 8; d = malloc(n); if(d == nil){ werrstr("out of memory"); return nil; } n = dec64(d, n, t, tt - t); if(n < 0){ free(d); werrstr("incorrect .pem file format: bad base64 encoded data"); return nil; } *len = n; return d; } drawterm-20170818/libsec/des.c000066400000000000000000000421301314554504700160030ustar00rootroot00000000000000#include "os.h" #include /* * integrated sbox & p perm */ static u32int spbox[] = { 0x00808200,0x00000000,0x00008000,0x00808202,0x00808002,0x00008202,0x00000002,0x00008000, 0x00000200,0x00808200,0x00808202,0x00000200,0x00800202,0x00808002,0x00800000,0x00000002, 0x00000202,0x00800200,0x00800200,0x00008200,0x00008200,0x00808000,0x00808000,0x00800202, 0x00008002,0x00800002,0x00800002,0x00008002,0x00000000,0x00000202,0x00008202,0x00800000, 0x00008000,0x00808202,0x00000002,0x00808000,0x00808200,0x00800000,0x00800000,0x00000200, 0x00808002,0x00008000,0x00008200,0x00800002,0x00000200,0x00000002,0x00800202,0x00008202, 0x00808202,0x00008002,0x00808000,0x00800202,0x00800002,0x00000202,0x00008202,0x00808200, 0x00000202,0x00800200,0x00800200,0x00000000,0x00008002,0x00008200,0x00000000,0x00808002, 0x40084010,0x40004000,0x00004000,0x00084010,0x00080000,0x00000010,0x40080010,0x40004010, 0x40000010,0x40084010,0x40084000,0x40000000,0x40004000,0x00080000,0x00000010,0x40080010, 0x00084000,0x00080010,0x40004010,0x00000000,0x40000000,0x00004000,0x00084010,0x40080000, 0x00080010,0x40000010,0x00000000,0x00084000,0x00004010,0x40084000,0x40080000,0x00004010, 0x00000000,0x00084010,0x40080010,0x00080000,0x40004010,0x40080000,0x40084000,0x00004000, 0x40080000,0x40004000,0x00000010,0x40084010,0x00084010,0x00000010,0x00004000,0x40000000, 0x00004010,0x40084000,0x00080000,0x40000010,0x00080010,0x40004010,0x40000010,0x00080010, 0x00084000,0x00000000,0x40004000,0x00004010,0x40000000,0x40080010,0x40084010,0x00084000, 0x00000104,0x04010100,0x00000000,0x04010004,0x04000100,0x00000000,0x00010104,0x04000100, 0x00010004,0x04000004,0x04000004,0x00010000,0x04010104,0x00010004,0x04010000,0x00000104, 0x04000000,0x00000004,0x04010100,0x00000100,0x00010100,0x04010000,0x04010004,0x00010104, 0x04000104,0x00010100,0x00010000,0x04000104,0x00000004,0x04010104,0x00000100,0x04000000, 0x04010100,0x04000000,0x00010004,0x00000104,0x00010000,0x04010100,0x04000100,0x00000000, 0x00000100,0x00010004,0x04010104,0x04000100,0x04000004,0x00000100,0x00000000,0x04010004, 0x04000104,0x00010000,0x04000000,0x04010104,0x00000004,0x00010104,0x00010100,0x04000004, 0x04010000,0x04000104,0x00000104,0x04010000,0x00010104,0x00000004,0x04010004,0x00010100, 0x80401000,0x80001040,0x80001040,0x00000040,0x00401040,0x80400040,0x80400000,0x80001000, 0x00000000,0x00401000,0x00401000,0x80401040,0x80000040,0x00000000,0x00400040,0x80400000, 0x80000000,0x00001000,0x00400000,0x80401000,0x00000040,0x00400000,0x80001000,0x00001040, 0x80400040,0x80000000,0x00001040,0x00400040,0x00001000,0x00401040,0x80401040,0x80000040, 0x00400040,0x80400000,0x00401000,0x80401040,0x80000040,0x00000000,0x00000000,0x00401000, 0x00001040,0x00400040,0x80400040,0x80000000,0x80401000,0x80001040,0x80001040,0x00000040, 0x80401040,0x80000040,0x80000000,0x00001000,0x80400000,0x80001000,0x00401040,0x80400040, 0x80001000,0x00001040,0x00400000,0x80401000,0x00000040,0x00400000,0x00001000,0x00401040, 0x00000080,0x01040080,0x01040000,0x21000080,0x00040000,0x00000080,0x20000000,0x01040000, 0x20040080,0x00040000,0x01000080,0x20040080,0x21000080,0x21040000,0x00040080,0x20000000, 0x01000000,0x20040000,0x20040000,0x00000000,0x20000080,0x21040080,0x21040080,0x01000080, 0x21040000,0x20000080,0x00000000,0x21000000,0x01040080,0x01000000,0x21000000,0x00040080, 0x00040000,0x21000080,0x00000080,0x01000000,0x20000000,0x01040000,0x21000080,0x20040080, 0x01000080,0x20000000,0x21040000,0x01040080,0x20040080,0x00000080,0x01000000,0x21040000, 0x21040080,0x00040080,0x21000000,0x21040080,0x01040000,0x00000000,0x20040000,0x21000000, 0x00040080,0x01000080,0x20000080,0x00040000,0x00000000,0x20040000,0x01040080,0x20000080, 0x10000008,0x10200000,0x00002000,0x10202008,0x10200000,0x00000008,0x10202008,0x00200000, 0x10002000,0x00202008,0x00200000,0x10000008,0x00200008,0x10002000,0x10000000,0x00002008, 0x00000000,0x00200008,0x10002008,0x00002000,0x00202000,0x10002008,0x00000008,0x10200008, 0x10200008,0x00000000,0x00202008,0x10202000,0x00002008,0x00202000,0x10202000,0x10000000, 0x10002000,0x00000008,0x10200008,0x00202000,0x10202008,0x00200000,0x00002008,0x10000008, 0x00200000,0x10002000,0x10000000,0x00002008,0x10000008,0x10202008,0x00202000,0x10200000, 0x00202008,0x10202000,0x00000000,0x10200008,0x00000008,0x00002000,0x10200000,0x00202008, 0x00002000,0x00200008,0x10002008,0x00000000,0x10202000,0x10000000,0x00200008,0x10002008, 0x00100000,0x02100001,0x02000401,0x00000000,0x00000400,0x02000401,0x00100401,0x02100400, 0x02100401,0x00100000,0x00000000,0x02000001,0x00000001,0x02000000,0x02100001,0x00000401, 0x02000400,0x00100401,0x00100001,0x02000400,0x02000001,0x02100000,0x02100400,0x00100001, 0x02100000,0x00000400,0x00000401,0x02100401,0x00100400,0x00000001,0x02000000,0x00100400, 0x02000000,0x00100400,0x00100000,0x02000401,0x02000401,0x02100001,0x02100001,0x00000001, 0x00100001,0x02000000,0x02000400,0x00100000,0x02100400,0x00000401,0x00100401,0x02100400, 0x00000401,0x02000001,0x02100401,0x02100000,0x00100400,0x00000000,0x00000001,0x02100401, 0x00000000,0x00100401,0x02100000,0x00000400,0x02000001,0x02000400,0x00000400,0x00100001, 0x08000820,0x00000800,0x00020000,0x08020820,0x08000000,0x08000820,0x00000020,0x08000000, 0x00020020,0x08020000,0x08020820,0x00020800,0x08020800,0x00020820,0x00000800,0x00000020, 0x08020000,0x08000020,0x08000800,0x00000820,0x00020800,0x00020020,0x08020020,0x08020800, 0x00000820,0x00000000,0x00000000,0x08020020,0x08000020,0x08000800,0x00020820,0x00020000, 0x00020820,0x00020000,0x08020800,0x00000800,0x00000020,0x08020020,0x00000800,0x00020820, 0x08000800,0x00000020,0x08000020,0x08020000,0x08020020,0x08000000,0x00020000,0x08000820, 0x00000000,0x08020820,0x00020020,0x08000020,0x08020000,0x08000800,0x08000820,0x00000000, 0x08020820,0x00020800,0x00020800,0x00000820,0x00000820,0x00020020,0x08000000,0x08020800, }; /* * for manual index calculation * #define fetch(box, i, sh) (*((u32int*)((uchar*)spbox + (box << 8) + ((i >> (sh)) & 0xfc)))) */ #define fetch(box, i, sh) ((spbox+(box << 6))[((i >> (sh + 2)) & 0x3f)]) /* * DES electronic codebook encryption of one block */ void block_cipher(ulong key[32], uchar text[8], int decrypting) { u32int right, left, v0, v1; int i, keystep; /* * initial permutation */ v0 = text[0] | ((u32int)text[2]<<8) | ((u32int)text[4]<<16) | ((u32int)text[6]<<24); left = text[1] | ((u32int)text[3]<<8) | ((u32int)text[5]<<16) | ((u32int)text[7]<<24); right = (left & 0xaaaaaaaa) | ((v0 >> 1) & 0x55555555); left = ((left << 1) & 0xaaaaaaaa) | (v0 & 0x55555555); left = ((left << 6) & 0x33003300) | (left & 0xcc33cc33) | ((left >> 6) & 0x00cc00cc); left = ((left << 12) & 0x0f0f0000) | (left & 0xf0f00f0f) | ((left >> 12) & 0x0000f0f0); right = ((right << 6) & 0x33003300) | (right & 0xcc33cc33) | ((right >> 6) & 0x00cc00cc); right = ((right << 12) & 0x0f0f0000) | (right & 0xf0f00f0f) | ((right >> 12) & 0x0000f0f0); if (decrypting) { keystep = -2; key = key + 32 - 2; } else keystep = 2; for (i = 0; i < 8; i++) { v0 = key[0]; v0 ^= (right >> 1) | (right << 31); left ^= fetch(0, v0, 24) ^ fetch(2, v0, 16) ^ fetch(4, v0, 8) ^ fetch(6, v0, 0); v1 = key[1]; v1 ^= (right << 3) | (right >> 29); left ^= fetch(1, v1, 24) ^ fetch(3, v1, 16) ^ fetch(5, v1, 8) ^ fetch(7, v1, 0); key += keystep; v0 = key[0]; v0 ^= (left >> 1) | (left << 31); right ^= fetch(0, v0, 24) ^ fetch(2, v0, 16) ^ fetch(4, v0, 8) ^ fetch(6, v0, 0); v1 = key[1]; v1 ^= (left << 3) | (left >> 29); right ^= fetch(1, v1, 24) ^ fetch(3, v1, 16) ^ fetch(5, v1, 8) ^ fetch(7, v1, 0); key += keystep; } /* * final permutation, inverse initial permutation */ v0 = ((left << 1) & 0xaaaaaaaa) | (right & 0x55555555); v1 = (left & 0xaaaaaaaa) | ((right >> 1) & 0x55555555); v1 = ((v1 << 6) & 0x33003300) | (v1 & 0xcc33cc33) | ((v1 >> 6) & 0x00cc00cc); v1 = ((v1 << 12) & 0x0f0f0000) | (v1 & 0xf0f00f0f) | ((v1 >> 12) & 0x0000f0f0); v0 = ((v0 << 6) & 0x33003300) | (v0 & 0xcc33cc33) | ((v0 >> 6) & 0x00cc00cc); v0 = ((v0 << 12) & 0x0f0f0000) | (v0 & 0xf0f00f0f) | ((v0 >> 12) & 0x0000f0f0); text[0] = v0; text[2] = v0 >> 8; text[4] = v0 >> 16; text[6] = v0 >> 24; text[1] = v1; text[3] = v1 >> 8; text[5] = v1 >> 16; text[7] = v1 >> 24; } /* * triple DES electronic codebook encryption of one block */ void triple_block_cipher(ulong expanded_key[3][32], uchar text[8], int ende) { ulong *key; u32int right, left, v0, v1; int i, j, keystep; /* * initial permutation */ v0 = text[0] | ((u32int)text[2]<<8) | ((u32int)text[4]<<16) | ((u32int)text[6]<<24); left = text[1] | ((u32int)text[3]<<8) | ((u32int)text[5]<<16) | ((u32int)text[7]<<24); right = (left & 0xaaaaaaaa) | ((v0 >> 1) & 0x55555555); left = ((left << 1) & 0xaaaaaaaa) | (v0 & 0x55555555); left = ((left << 6) & 0x33003300) | (left & 0xcc33cc33) | ((left >> 6) & 0x00cc00cc); left = ((left << 12) & 0x0f0f0000) | (left & 0xf0f00f0f) | ((left >> 12) & 0x0000f0f0); right = ((right << 6) & 0x33003300) | (right & 0xcc33cc33) | ((right >> 6) & 0x00cc00cc); right = ((right << 12) & 0x0f0f0000) | (right & 0xf0f00f0f) | ((right >> 12) & 0x0000f0f0); for(j = 0; j < 3; j++){ if((ende & 1) == DES3D) { key = &expanded_key[2-j][32-2]; keystep = -2; } else { key = &expanded_key[j][0]; keystep = 2; } ende >>= 1; for (i = 0; i < 8; i++) { v0 = key[0]; v0 ^= (right >> 1) | (right << 31); left ^= fetch(0, v0, 24) ^ fetch(2, v0, 16) ^ fetch(4, v0, 8) ^ fetch(6, v0, 0); v1 = key[1]; v1 ^= (right << 3) | (right >> 29); left ^= fetch(1, v1, 24) ^ fetch(3, v1, 16) ^ fetch(5, v1, 8) ^ fetch(7, v1, 0); key += keystep; v0 = key[0]; v0 ^= (left >> 1) | (left << 31); right ^= fetch(0, v0, 24) ^ fetch(2, v0, 16) ^ fetch(4, v0, 8) ^ fetch(6, v0, 0); v1 = key[1]; v1 ^= (left << 3) | (left >> 29); right ^= fetch(1, v1, 24) ^ fetch(3, v1, 16) ^ fetch(5, v1, 8) ^ fetch(7, v1, 0); key += keystep; } v0 = left; left = right; right = v0; } /* * final permutation, inverse initial permutation * left and right are swapped here */ v0 = ((right << 1) & 0xaaaaaaaa) | (left & 0x55555555); v1 = (right & 0xaaaaaaaa) | ((left >> 1) & 0x55555555); v1 = ((v1 << 6) & 0x33003300) | (v1 & 0xcc33cc33) | ((v1 >> 6) & 0x00cc00cc); v1 = ((v1 << 12) & 0x0f0f0000) | (v1 & 0xf0f00f0f) | ((v1 >> 12) & 0x0000f0f0); v0 = ((v0 << 6) & 0x33003300) | (v0 & 0xcc33cc33) | ((v0 >> 6) & 0x00cc00cc); v0 = ((v0 << 12) & 0x0f0f0000) | (v0 & 0xf0f00f0f) | ((v0 >> 12) & 0x0000f0f0); text[0] = v0; text[2] = v0 >> 8; text[4] = v0 >> 16; text[6] = v0 >> 24; text[1] = v1; text[3] = v1 >> 8; text[5] = v1 >> 16; text[7] = v1 >> 24; } /* * key compression permutation, 4 bits at a time */ static u32int comptab[] = { 0x000000,0x010000,0x000008,0x010008,0x000080,0x010080,0x000088,0x010088, 0x000000,0x010000,0x000008,0x010008,0x000080,0x010080,0x000088,0x010088, 0x000000,0x100000,0x000800,0x100800,0x000000,0x100000,0x000800,0x100800, 0x002000,0x102000,0x002800,0x102800,0x002000,0x102000,0x002800,0x102800, 0x000000,0x000004,0x000400,0x000404,0x000000,0x000004,0x000400,0x000404, 0x400000,0x400004,0x400400,0x400404,0x400000,0x400004,0x400400,0x400404, 0x000000,0x000020,0x008000,0x008020,0x800000,0x800020,0x808000,0x808020, 0x000002,0x000022,0x008002,0x008022,0x800002,0x800022,0x808002,0x808022, 0x000000,0x000200,0x200000,0x200200,0x001000,0x001200,0x201000,0x201200, 0x000000,0x000200,0x200000,0x200200,0x001000,0x001200,0x201000,0x201200, 0x000000,0x000040,0x000010,0x000050,0x004000,0x004040,0x004010,0x004050, 0x040000,0x040040,0x040010,0x040050,0x044000,0x044040,0x044010,0x044050, 0x000000,0x000100,0x020000,0x020100,0x000001,0x000101,0x020001,0x020101, 0x080000,0x080100,0x0a0000,0x0a0100,0x080001,0x080101,0x0a0001,0x0a0101, 0x000000,0x000100,0x040000,0x040100,0x000000,0x000100,0x040000,0x040100, 0x000040,0x000140,0x040040,0x040140,0x000040,0x000140,0x040040,0x040140, 0x000000,0x400000,0x008000,0x408000,0x000008,0x400008,0x008008,0x408008, 0x000400,0x400400,0x008400,0x408400,0x000408,0x400408,0x008408,0x408408, 0x000000,0x001000,0x080000,0x081000,0x000020,0x001020,0x080020,0x081020, 0x004000,0x005000,0x084000,0x085000,0x004020,0x005020,0x084020,0x085020, 0x000000,0x000800,0x000000,0x000800,0x000010,0x000810,0x000010,0x000810, 0x800000,0x800800,0x800000,0x800800,0x800010,0x800810,0x800010,0x800810, 0x000000,0x010000,0x000200,0x010200,0x000000,0x010000,0x000200,0x010200, 0x100000,0x110000,0x100200,0x110200,0x100000,0x110000,0x100200,0x110200, 0x000000,0x000004,0x000000,0x000004,0x000080,0x000084,0x000080,0x000084, 0x002000,0x002004,0x002000,0x002004,0x002080,0x002084,0x002080,0x002084, 0x000000,0x000001,0x200000,0x200001,0x020000,0x020001,0x220000,0x220001, 0x000002,0x000003,0x200002,0x200003,0x020002,0x020003,0x220002,0x220003, }; static int keysh[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, }; static void keycompperm(u32int left, u32int right, ulong *ek) { u32int v0, v1; int i; for(i = 0; i < 16; i++){ left = (left << keysh[i]) | (left >> (28 - keysh[i])); left &= 0xfffffff0; right = (right << keysh[i]) | (right >> (28 - keysh[i])); right &= 0xfffffff0; v0 = comptab[6 * (1 << 4) + ((left >> (32-4)) & 0xf)] | comptab[5 * (1 << 4) + ((left >> (32-8)) & 0xf)] | comptab[4 * (1 << 4) + ((left >> (32-12)) & 0xf)] | comptab[3 * (1 << 4) + ((left >> (32-16)) & 0xf)] | comptab[2 * (1 << 4) + ((left >> (32-20)) & 0xf)] | comptab[1 * (1 << 4) + ((left >> (32-24)) & 0xf)] | comptab[0 * (1 << 4) + ((left >> (32-28)) & 0xf)]; v1 = comptab[13 * (1 << 4) + ((right >> (32-4)) & 0xf)] | comptab[12 * (1 << 4) + ((right >> (32-8)) & 0xf)] | comptab[11 * (1 << 4) + ((right >> (32-12)) & 0xf)] | comptab[10 * (1 << 4) + ((right >> (32-16)) & 0xf)] | comptab[9 * (1 << 4) + ((right >> (32-20)) & 0xf)] | comptab[8 * (1 << 4) + ((right >> (32-24)) & 0xf)] | comptab[7 * (1 << 4) + ((right >> (32-28)) & 0xf)]; ek[0] = (((v0 >> (24-6)) & 0x3f) << 26) | (((v0 >> (24-18)) & 0x3f) << 18) | (((v1 >> (24-6)) & 0x3f) << 10) | (((v1 >> (24-18)) & 0x3f) << 2); ek[1] = (((v0 >> (24-12)) & 0x3f) << 26) | (((v0 >> (24-24)) & 0x3f) << 18) | (((v1 >> (24-12)) & 0x3f) << 10) | (((v1 >> (24-24)) & 0x3f) << 2); ek += 2; } } void des_key_setup(uchar key[8], ulong *ek) { u32int left, right, v0, v1; v0 = key[0] | ((u32int)key[2] << 8) | ((u32int)key[4] << 16) | ((u32int)key[6] << 24); v1 = key[1] | ((u32int)key[3] << 8) | ((u32int)key[5] << 16) | ((u32int)key[7] << 24); left = ((v0 >> 1) & 0x40404040) | ((v0 >> 2) & 0x10101010) | ((v0 >> 3) & 0x04040404) | ((v0 >> 4) & 0x01010101) | ((v1 >> 0) & 0x80808080) | ((v1 >> 1) & 0x20202020) | ((v1 >> 2) & 0x08080808) | ((v1 >> 3) & 0x02020202); right = ((v0 >> 1) & 0x04040404) | ((v0 << 2) & 0x10101010) | ((v0 << 5) & 0x40404040) | ((v1 << 0) & 0x08080808) | ((v1 << 3) & 0x20202020) | ((v1 << 6) & 0x80808080); left = ((left << 6) & 0x33003300) | (left & 0xcc33cc33) | ((left >> 6) & 0x00cc00cc); v0 = ((left << 12) & 0x0f0f0000) | (left & 0xf0f00f0f) | ((left >> 12) & 0x0000f0f0); right = ((right << 6) & 0x33003300) | (right & 0xcc33cc33) | ((right >> 6) & 0x00cc00cc); v1 = ((right << 12) & 0x0f0f0000) | (right & 0xf0f00f0f) | ((right >> 12) & 0x0000f0f0); left = v0 & 0xfffffff0; right = (v1 & 0xffffff00) | ((v0 << 4) & 0xf0); keycompperm(left, right, ek); } static uchar parity[128] = { 0x01, 0x02, 0x04, 0x07, 0x08, 0x0b, 0x0d, 0x0e, 0x10, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, 0x1f, 0x20, 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x2f, 0x31, 0x32, 0x34, 0x37, 0x38, 0x3b, 0x3d, 0x3e, 0x40, 0x43, 0x45, 0x46, 0x49, 0x4a, 0x4c, 0x4f, 0x51, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, 0x5e, 0x61, 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x6e, 0x70, 0x73, 0x75, 0x76, 0x79, 0x7a, 0x7c, 0x7f, 0x80, 0x83, 0x85, 0x86, 0x89, 0x8a, 0x8c, 0x8f, 0x91, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d, 0x9e, 0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xae, 0xb0, 0xb3, 0xb5, 0xb6, 0xb9, 0xba, 0xbc, 0xbf, 0xc1, 0xc2, 0xc4, 0xc7, 0xc8, 0xcb, 0xcd, 0xce, 0xd0, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc, 0xdf, 0xe0, 0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xef, 0xf1, 0xf2, 0xf4, 0xf7, 0xf8, 0xfb, 0xfd, 0xfe, }; /* * convert a 7 byte key to an 8 byte one */ void des56to64(uchar *k56, uchar *k64) { u32int hi, lo; hi = ((u32int)k56[0]<<24)|((u32int)k56[1]<<16)|((u32int)k56[2]<<8)|k56[3]; lo = ((u32int)k56[4]<<24)|((u32int)k56[5]<<16)|((u32int)k56[6]<<8); k64[0] = parity[(hi>>25)&0x7f]; k64[1] = parity[(hi>>18)&0x7f]; k64[2] = parity[(hi>>11)&0x7f]; k64[3] = parity[(hi>>4)&0x7f]; k64[4] = parity[((hi<<3)|(lo>>29))&0x7f]; k64[5] = parity[(lo>>22)&0x7f]; k64[6] = parity[(lo>>15)&0x7f]; k64[7] = parity[(lo>>8)&0x7f]; } /* * convert an 8 byte key to a 7 byte one */ void des64to56(uchar *k64, uchar *k56) { u32int hi, lo; hi = (((u32int)k64[0]&0xfe)<<24)|(((u32int)k64[1]&0xfe)<<17)|(((u32int)k64[2]&0xfe)<<10) |((k64[3]&0xfe)<<3)|(k64[4]>>4); lo = (((u32int)k64[4]&0xfe)<<28)|(((u32int)k64[5]&0xfe)<<21)|(((u32int)k64[6]&0xfe)<<14) |(((u32int)k64[7]&0xfe)<<7); k56[0] = hi>>24; k56[1] = hi>>16; k56[2] = hi>>8; k56[3] = hi>>0; k56[4] = lo>>24; k56[5] = lo>>16; k56[6] = lo>>8; } void key_setup(uchar key[7], ulong *ek) { uchar k64[8]; des56to64(key, k64); des_key_setup(k64, ek); } drawterm-20170818/libsec/des3CBC.c000066400000000000000000000021571314554504700164030ustar00rootroot00000000000000#include "os.h" #include #include // Because of the way that non multiple of 8 // buffers are handled, the decryptor must // be fed buffers of the same size as the // encryptor // If the length is not a multiple of 8, I encrypt // the overflow to be compatible with lacy's cryptlib void des3CBCencrypt(uchar *p, int len, DES3state *s) { uchar *p2, *ip, *eip; for(; len >= 8; len -= 8){ p2 = p; ip = s->ivec; for(eip = ip+8; ip < eip; ) *p2++ ^= *ip++; triple_block_cipher(s->expanded, p, DES3EDE); memmove(s->ivec, p, 8); p += 8; } if(len > 0){ ip = s->ivec; triple_block_cipher(s->expanded, ip, DES3EDE); for(eip = ip+len; ip < eip; ) *p++ ^= *ip++; } } void des3CBCdecrypt(uchar *p, int len, DES3state *s) { uchar *ip, *eip, *tp; uchar tmp[8]; for(; len >= 8; len -= 8){ memmove(tmp, p, 8); triple_block_cipher(s->expanded, p, DES3DED); tp = tmp; ip = s->ivec; for(eip = ip+8; ip < eip; ){ *p++ ^= *ip; *ip++ = *tp++; } } if(len > 0){ ip = s->ivec; triple_block_cipher(s->expanded, ip, DES3EDE); for(eip = ip+len; ip < eip; ) *p++ ^= *ip++; } } drawterm-20170818/libsec/des3ECB.c000066400000000000000000000016251314554504700164040ustar00rootroot00000000000000#include "os.h" #include #include // I wasn't sure what to do when the buffer was not // a multiple of 8. I did what lacy's cryptolib did // to be compatible, but it looks dangerous to me // since its encrypting plain text with the key. -- presotto void des3ECBencrypt(uchar *p, int len, DES3state *s) { int i; uchar tmp[8]; for(; len >= 8; len -= 8){ triple_block_cipher(s->expanded, p, DES3EDE); p += 8; } if(len > 0){ for (i=0; i<8; i++) tmp[i] = i; triple_block_cipher(s->expanded, tmp, DES3EDE); for (i = 0; i < len; i++) p[i] ^= tmp[i]; } } void des3ECBdecrypt(uchar *p, int len, DES3state *s) { int i; uchar tmp[8]; for(; len >= 8; len -= 8){ triple_block_cipher(s->expanded, p, DES3DED); p += 8; } if(len > 0){ for (i=0; i<8; i++) tmp[i] = i; triple_block_cipher(s->expanded, tmp, DES3EDE); for (i = 0; i < len; i++) p[i] ^= tmp[i]; } } drawterm-20170818/libsec/desCBC.c000066400000000000000000000020671314554504700163200ustar00rootroot00000000000000#include "os.h" #include #include // Because of the way that non multiple of 8 // buffers are handled, the decryptor must // be fed buffers of the same size as the // encryptor // If the length is not a multiple of 8, I encrypt // the overflow to be compatible with lacy's cryptlib void desCBCencrypt(uchar *p, int len, DESstate *s) { uchar *p2, *ip, *eip; for(; len >= 8; len -= 8){ p2 = p; ip = s->ivec; for(eip = ip+8; ip < eip; ) *p2++ ^= *ip++; block_cipher(s->expanded, p, 0); memmove(s->ivec, p, 8); p += 8; } if(len > 0){ ip = s->ivec; block_cipher(s->expanded, ip, 0); for(eip = ip+len; ip < eip; ) *p++ ^= *ip++; } } void desCBCdecrypt(uchar *p, int len, DESstate *s) { uchar *ip, *eip, *tp; uchar tmp[8]; for(; len >= 8; len -= 8){ memmove(tmp, p, 8); block_cipher(s->expanded, p, 1); tp = tmp; ip = s->ivec; for(eip = ip+8; ip < eip; ){ *p++ ^= *ip; *ip++ = *tp++; } } if(len > 0){ ip = s->ivec; block_cipher(s->expanded, ip, 0); for(eip = ip+len; ip < eip; ) *p++ ^= *ip++; } } drawterm-20170818/libsec/desECB.c000066400000000000000000000015351314554504700163210ustar00rootroot00000000000000#include "os.h" #include #include // I wasn't sure what to do when the buffer was not // a multiple of 8. I did what lacy's cryptolib did // to be compatible, but it looks dangerous to me // since its encrypting plain text with the key. -- presotto void desECBencrypt(uchar *p, int len, DESstate *s) { int i; uchar tmp[8]; for(; len >= 8; len -= 8){ block_cipher(s->expanded, p, 0); p += 8; } if(len > 0){ for (i=0; i<8; i++) tmp[i] = i; block_cipher(s->expanded, tmp, 0); for (i = 0; i < len; i++) p[i] ^= tmp[i]; } } void desECBdecrypt(uchar *p, int len, DESstate *s) { int i; uchar tmp[8]; for(; len >= 8; len -= 8){ block_cipher(s->expanded, p, 1); p += 8; } if(len > 0){ for (i=0; i<8; i++) tmp[i] = i; block_cipher(s->expanded, tmp, 0); for (i = 0; i < len; i++) p[i] ^= tmp[i]; } } drawterm-20170818/libsec/desmodes.c000066400000000000000000000012071314554504700170330ustar00rootroot00000000000000#include "os.h" #include /* * these routines use the 64bit format for * DES keys. */ void setupDESstate(DESstate *s, uchar key[8], uchar *ivec) { memset(s, 0, sizeof(*s)); memmove(s->key, key, sizeof(s->key)); des_key_setup(key, s->expanded); if(ivec) memmove(s->ivec, ivec, 8); s->setup = 0xdeadbeef; } void setupDES3state(DES3state *s, uchar key[3][8], uchar *ivec) { memset(s, 0, sizeof(*s)); memmove(s->key, key, sizeof(s->key)); des_key_setup(key[0], s->expanded[0]); des_key_setup(key[1], s->expanded[1]); des_key_setup(key[2], s->expanded[2]); if(ivec) memmove(s->ivec, ivec, 8); s->setup = 0xdeadbeef; } drawterm-20170818/libsec/dsaalloc.c000066400000000000000000000015401314554504700170120ustar00rootroot00000000000000#include "os.h" #include #include DSApub* dsapuballoc(void) { DSApub *dsa; dsa = mallocz(sizeof(*dsa), 1); if(dsa == nil) sysfatal("dsapuballoc"); return dsa; } void dsapubfree(DSApub *dsa) { if(dsa == nil) return; mpfree(dsa->p); mpfree(dsa->q); mpfree(dsa->alpha); mpfree(dsa->key); } DSApriv* dsaprivalloc(void) { DSApriv *dsa; dsa = mallocz(sizeof(*dsa), 1); if(dsa == nil) sysfatal("dsaprivalloc"); return dsa; } void dsaprivfree(DSApriv *dsa) { if(dsa == nil) return; mpfree(dsa->pub.p); mpfree(dsa->pub.q); mpfree(dsa->pub.alpha); mpfree(dsa->pub.key); mpfree(dsa->secret); } DSAsig* dsasigalloc(void) { DSAsig *dsa; dsa = mallocz(sizeof(*dsa), 1); if(dsa == nil) sysfatal("dsasigalloc"); return dsa; } void dsasigfree(DSAsig *dsa) { if(dsa == nil) return; mpfree(dsa->r); mpfree(dsa->s); } drawterm-20170818/libsec/dsagen.c000066400000000000000000000023251314554504700164730ustar00rootroot00000000000000#include "os.h" #include #include DSApriv* dsagen(DSApub *opub) { DSApub *pub; DSApriv *priv; mpint *exp; mpint *g; mpint *r; int bits; priv = dsaprivalloc(); pub = &priv->pub; if(opub != nil){ pub->p = mpcopy(opub->p); pub->q = mpcopy(opub->q); } else { pub->p = mpnew(0); pub->q = mpnew(0); DSAprimes(pub->q, pub->p, nil); } bits = Dbits*pub->p->top; pub->alpha = mpnew(0); pub->key = mpnew(0); priv->secret = mpnew(0); // find a generator alpha of the multiplicative // group Z*p, i.e., of order n = p-1. We use the // fact that q divides p-1 to reduce the exponent. // // This isn't very efficient. If anyone has a better // idea, mail presotto@closedmind.org exp = mpnew(0); g = mpnew(0); r = mpnew(0); mpsub(pub->p, mpone, exp); mpdiv(exp, pub->q, exp, r); if(mpcmp(r, mpzero) != 0) sysfatal("dsagen foul up"); while(1){ mprand(bits, genrandom, g); mpmod(g, pub->p, g); mpexp(g, exp, pub->p, pub->alpha); if(mpcmp(pub->alpha, mpone) != 0) break; } mpfree(g); mpfree(exp); // create the secret key mprand(bits, genrandom, priv->secret); mpmod(priv->secret, pub->p, priv->secret); mpexp(pub->alpha, priv->secret, pub->p, pub->key); return priv; } drawterm-20170818/libsec/dsaprimes.c000066400000000000000000000035311314554504700172210ustar00rootroot00000000000000#include "os.h" #include #include // NIST algorithm for generating DSA primes // Menezes et al (1997) Handbook of Applied Cryptography, p.151 // q is a 160-bit prime; p is a 1024-bit prime; q divides p-1 // arithmetic on unsigned ints mod 2**160, represented // as 20-byte, little-endian uchar array static void Hrand(uchar *s) { ulong *u = (ulong*)s; *u++ = fastrand(); *u++ = fastrand(); *u++ = fastrand(); *u++ = fastrand(); *u = fastrand(); } static void Hincr(uchar *s) { int i; for(i=0; i<20; i++) if(++s[i]!=0) break; } // this can run for quite a while; be patient void DSAprimes(mpint *q, mpint *p, uchar seed[SHA1dlen]) { int i, j, k, n = 6, b = 63; uchar s[SHA1dlen], Hs[SHA1dlen], Hs1[SHA1dlen], sj[SHA1dlen], sjk[SHA1dlen]; mpint *two1023, *mb, *Vk, *W, *X, *q2; two1023 = mpnew(1024); mpleft(mpone, 1023, two1023); mb = mpnew(0); mpleft(mpone, b, mb); W = mpnew(1024); Vk = mpnew(1024); X = mpnew(0); q2 = mpnew(0); forever: do{ Hrand(s); memcpy(sj, s, 20); sha1(s, 20, Hs, 0); Hincr(sj); sha1(sj, 20, Hs1, 0); for(i=0; i<20; i++) Hs[i] ^= Hs1[i]; Hs[0] |= 1; Hs[19] |= 0x80; letomp(Hs, 20, q); }while(!probably_prime(q, 18)); if(seed != nil) // allow skeptics to confirm computation memmove(seed, s, SHA1dlen); i = 0; j = 2; Hincr(sj); mpleft(q, 1, q2); while(i<4096){ memcpy(sjk, sj, 20); for(k=0; k <= n; k++){ sha1(sjk, 20, Hs, 0); letomp(Hs, 20, Vk); if(k == n) mpmod(Vk, mb, Vk); mpleft(Vk, 160*k, Vk); mpadd(W, Vk, W); Hincr(sjk); } mpadd(W, two1023, X); mpmod(X, q2, W); mpsub(W, mpone, W); mpsub(X, W, p); if(mpcmp(p, two1023)>=0 && probably_prime(p, 5)) goto done; i += 1; j += n+1; for(k=0; k #include DSApub* dsaprivtopub(DSApriv *priv) { DSApub *pub; pub = dsapuballoc(); pub->p = mpcopy(priv->pub.p); pub->q = mpcopy(priv->pub.q); pub->alpha = mpcopy(priv->pub.alpha); pub->key = mpcopy(priv->pub.key); return pub; } drawterm-20170818/libsec/dsasign.c000066400000000000000000000016461314554504700166670ustar00rootroot00000000000000#include "os.h" #include #include DSAsig* dsasign(DSApriv *priv, mpint *m) { DSApub *pub = &priv->pub; DSAsig *sig; mpint *qm1, *k, *kinv, *r, *s; mpint *q = pub->q, *p = pub->p, *alpha = pub->alpha; int qlen = mpsignif(q); qm1 = mpnew(0); kinv = mpnew(0); r = mpnew(0); s = mpnew(0); k = mpnew(0); mpsub(pub->q, mpone, qm1); // find a k that has an inverse mod q while(1){ mprand(qlen, genrandom, k); if((mpcmp(mpone, k) > 0) || (mpcmp(k, qm1) >= 0)) continue; mpextendedgcd(k, q, r, kinv, s); if(mpcmp(r, mpone) != 0) continue; break; } // make kinv positive mpmod(kinv, qm1, kinv); // r = ((alpha**k) mod p) mod q mpexp(alpha, k, p, r); mpmod(r, q, r); // s = (kinv*(m + ar)) mod q mpmul(r, priv->secret, s); mpadd(s, m, s); mpmul(s, kinv, s); mpmod(s, q, s); sig = dsasigalloc(); sig->r = r; sig->s = s; mpfree(qm1); mpfree(k); mpfree(kinv); return sig; } drawterm-20170818/libsec/dsaverify.c000066400000000000000000000016151314554504700172270ustar00rootroot00000000000000#include "os.h" #include #include int dsaverify(DSApub *pub, DSAsig *sig, mpint *m) { int rv = -1; mpint *u1, *u2, *v, *sinv; if(sig->r->sign < 0 || mpcmp(sig->r, pub->q) >= 0) return rv; if(sig->s->sign < 0 || mpcmp(sig->s, pub->q) >= 0) return rv; u1 = mpnew(0); u2 = mpnew(0); v = mpnew(0); sinv = mpnew(0); // find (s**-1) mod q, make sure it exists mpextendedgcd(sig->s, pub->q, u1, sinv, v); if(mpcmp(u1, mpone) != 0) goto out; // u1 = (sinv * m) mod q, u2 = (r * sinv) mod q mpmul(sinv, m, u1); mpmod(u1, pub->q, u1); mpmul(sig->r, sinv, u2); mpmod(u2, pub->q, u2); // v = (((alpha**u1)*(key**u2)) mod p) mod q mpexp(pub->alpha, u1, pub->p, sinv); mpexp(pub->key, u2, pub->p, v); mpmul(sinv, v, v); mpmod(v, pub->p, v); mpmod(v, pub->q, v); if(mpcmp(v, sig->r) == 0) rv = 0; out: mpfree(v); mpfree(u1); mpfree(u2); mpfree(sinv); return rv; } drawterm-20170818/libsec/egalloc.c000066400000000000000000000014121314554504700166340ustar00rootroot00000000000000#include "os.h" #include #include EGpub* egpuballoc(void) { EGpub *eg; eg = mallocz(sizeof(*eg), 1); if(eg == nil) sysfatal("egpuballoc"); return eg; } void egpubfree(EGpub *eg) { if(eg == nil) return; mpfree(eg->p); mpfree(eg->alpha); mpfree(eg->key); } EGpriv* egprivalloc(void) { EGpriv *eg; eg = mallocz(sizeof(*eg), 1); if(eg == nil) sysfatal("egprivalloc"); return eg; } void egprivfree(EGpriv *eg) { if(eg == nil) return; mpfree(eg->pub.p); mpfree(eg->pub.alpha); mpfree(eg->pub.key); mpfree(eg->secret); } EGsig* egsigalloc(void) { EGsig *eg; eg = mallocz(sizeof(*eg), 1); if(eg == nil) sysfatal("egsigalloc"); return eg; } void egsigfree(EGsig *eg) { if(eg == nil) return; mpfree(eg->r); mpfree(eg->s); } drawterm-20170818/libsec/egdecrypt.c000066400000000000000000000010641314554504700172170ustar00rootroot00000000000000#include "os.h" #include #include mpint* egdecrypt(EGpriv *priv, mpint *in, mpint *out) { EGpub *pub = &priv->pub; mpint *gamma, *delta; mpint *p = pub->p; int plen = mpsignif(p)+1; int shift = ((plen+Dbits-1)/Dbits)*Dbits; if(out == nil) out = mpnew(0); gamma = mpnew(0); delta = mpnew(0); mpright(in, shift, gamma); mpleft(gamma, shift, delta); mpsub(in, delta, delta); mpexp(gamma, priv->secret, p, out); mpinvert(out, p, gamma); mpmul(gamma, delta, out); mpmod(out, p, out); mpfree(gamma); mpfree(delta); return out; } drawterm-20170818/libsec/egencrypt.c000066400000000000000000000014461314554504700172350ustar00rootroot00000000000000#include "os.h" #include #include mpint* egencrypt(EGpub *pub, mpint *in, mpint *out) { mpint *m, *k, *gamma, *delta, *pm1; mpint *p = pub->p, *alpha = pub->alpha; int plen = mpsignif(p); int shift = ((plen+Dbits)/Dbits)*Dbits; // in libcrypt version, (int)(LENGTH(pub->p)*sizeof(NumType)*CHARBITS); if(out == nil) out = mpnew(0); pm1 = mpnew(0); m = mpnew(0); gamma = mpnew(0); delta = mpnew(0); mpmod(in, p, m); while(1){ k = mprand(plen, genrandom, nil); if((mpcmp(mpone, k) <= 0) && (mpcmp(k, pm1) < 0)) break; } mpexp(alpha, k, p, gamma); mpexp(pub->key, k, p, delta); mpmul(m, delta, delta); mpmod(delta, p, delta); mpleft(gamma, shift, out); mpadd(delta, out, out); mpfree(pm1); mpfree(m); mpfree(k); mpfree(gamma); mpfree(delta); return out; } drawterm-20170818/libsec/eggen.c000066400000000000000000000006351314554504700163210ustar00rootroot00000000000000#include "os.h" #include #include EGpriv* eggen(int nlen, int rounds) { EGpub *pub; EGpriv *priv; priv = egprivalloc(); pub = &priv->pub; pub->p = mpnew(0); pub->alpha = mpnew(0); pub->key = mpnew(0); priv->secret = mpnew(0); gensafeprime(pub->p, pub->alpha, nlen, rounds); mprand(nlen-1, genrandom, priv->secret); mpexp(pub->alpha, priv->secret, pub->p, pub->key); return priv; } drawterm-20170818/libsec/egprivtopub.c000066400000000000000000000004211314554504700175730ustar00rootroot00000000000000#include "os.h" #include #include EGpub* egprivtopub(EGpriv *priv) { EGpub *pub; pub = egpuballoc(); if(pub == nil) return nil; pub->p = mpcopy(priv->pub.p); pub->alpha = mpcopy(priv->pub.alpha); pub->key = mpcopy(priv->pub.key); return pub; } drawterm-20170818/libsec/egsign.c000066400000000000000000000014471314554504700165120ustar00rootroot00000000000000#include "os.h" #include #include EGsig* egsign(EGpriv *priv, mpint *m) { EGpub *pub = &priv->pub; EGsig *sig; mpint *pm1, *k, *kinv, *r, *s; mpint *p = pub->p, *alpha = pub->alpha; int plen = mpsignif(p); pm1 = mpnew(0); kinv = mpnew(0); r = mpnew(0); s = mpnew(0); k = mpnew(0); mpsub(p, mpone, pm1); while(1){ mprand(plen, genrandom, k); if((mpcmp(mpone, k) > 0) || (mpcmp(k, pm1) >= 0)) continue; mpextendedgcd(k, pm1, r, kinv, s); if(mpcmp(r, mpone) != 0) continue; break; } mpmod(kinv, pm1, kinv); // make kinv positive mpexp(alpha, k, p, r); mpmul(priv->secret, r, s); mpmod(s, pm1, s); mpsub(m, s, s); mpmul(kinv, s, s); mpmod(s, pm1, s); sig = egsigalloc(); sig->r = r; sig->s = s; mpfree(pm1); mpfree(k); mpfree(kinv); return sig; } drawterm-20170818/libsec/egtest.c000066400000000000000000000012171314554504700165240ustar00rootroot00000000000000#include "os.h" #include #include void main(void) { EGpriv *sk; mpint *m, *gamma, *delta, *in, *out; int plen, shift; fmtinstall('B', mpconv); sk = egprivalloc(); sk->pub.p = uitomp(2357, nil); sk->pub.alpha = uitomp(2, nil); sk->pub.key = uitomp(1185, nil); sk->secret = uitomp(1751, nil); m = uitomp(2035, nil); plen = mpsignif(sk->pub.p)+1; shift = ((plen+Dbits-1)/Dbits)*Dbits; gamma = uitomp(1430, nil); delta = uitomp(697, nil); out = mpnew(0); in = mpnew(0); mpleft(gamma, shift, in); mpadd(delta, in, in); egdecrypt(sk, in, out); if(mpcmp(m, out) != 0) print("decrypt failed to recover message\n"); } drawterm-20170818/libsec/egverify.c000066400000000000000000000010071314554504700170460ustar00rootroot00000000000000#include "os.h" #include #include int egverify(EGpub *pub, EGsig *sig, mpint *m) { mpint *p = pub->p, *alpha = pub->alpha; mpint *r = sig->r, *s = sig->s; mpint *v1, *v2, *rs; int rv = -1; if(mpcmp(r, mpone) < 0 || mpcmp(r, p) >= 0) return rv; v1 = mpnew(0); rs = mpnew(0); v2 = mpnew(0); mpexp(pub->key, r, p, v1); mpexp(r, s, p, rs); mpmul(v1, rs, v1); mpmod(v1, p, v1); mpexp(alpha, m, p, v2); if(mpcmp(v1, v2) == 0) rv = 0; mpfree(v1); mpfree(rs); mpfree(v2); return rv; } drawterm-20170818/libsec/fastrand.c000066400000000000000000000004021314554504700170260ustar00rootroot00000000000000#include #include #include /* * use the X917 random number generator to create random * numbers (faster than truerand() but not as random). */ ulong fastrand(void) { ulong x; genrandom((uchar*)&x, sizeof x); return x; } drawterm-20170818/libsec/genprime.c000066400000000000000000000010271314554504700170360ustar00rootroot00000000000000#include "os.h" #include #include // generate a probable prime. accuracy is the miller-rabin interations void genprime(mpint *p, int n, int accuracy) { mpdigit x; // generate n random bits with high and low bits set mpbits(p, n); genrandom((uchar*)p->p, (n+7)/8); p->top = (n+Dbits-1)/Dbits; x = 1; x <<= ((n-1)%Dbits); p->p[p->top-1] &= (x-1); p->p[p->top-1] |= x; p->p[0] |= 1; // keep icrementing till it looks prime for(;;){ if(probably_prime(p, accuracy)) break; mpadd(p, mptwo, p); } } drawterm-20170818/libsec/genrandom.c000066400000000000000000000022231314554504700172010ustar00rootroot00000000000000#include "os.h" #include #include typedef struct State{ QLock lock; int seeded; uvlong seed; DES3state des3; } State; static State x917state; static void X917(uchar *rand, int nrand) { int i, m, n8; uvlong I, x; /* 1. Compute intermediate value I = Ek(time). */ I = nsec(); triple_block_cipher(x917state.des3.expanded, (uchar*)&I, 0); /* two-key EDE */ /* 2. x[i] = Ek(I^seed); seed = Ek(x[i]^I); */ m = (nrand+7)/8; for(i=0; i8) ? 8 : nrand; memcpy(rand, (uchar*)&x, n8); rand += 8; nrand -= 8; x ^= I; triple_block_cipher(x917state.des3.expanded, (uchar*)&x, 0); x917state.seed = x; } } static void X917init(void) { int n; uchar mix[128]; uchar key3[3][8]; ulong *ulp; ulp = (ulong*)key3; for(n = 0; n < sizeof(key3)/sizeof(ulong); n++) ulp[n] = truerand(); setupDES3state(&x917state.des3, key3, nil); X917(mix, sizeof mix); x917state.seeded = 1; } void genrandom(uchar *p, int n) { qlock(&x917state.lock); if(x917state.seeded == 0) X917init(); X917(p, n); qunlock(&x917state.lock); } drawterm-20170818/libsec/gensafeprime.c000066400000000000000000000013451314554504700177000ustar00rootroot00000000000000#include "os.h" #include #include // find a prime p of length n and a generator alpha of Z^*_p // Alg 4.86 Menezes et al () Handbook, p.164 void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy) { mpint *q, *b; q = mpnew(n-1); while(1){ genprime(q, n-1, accuracy); mpleft(q, 1, p); mpadd(p, mpone, p); // p = 2*q+1 if(probably_prime(p, accuracy)) break; } // now find a generator alpha of the multiplicative // group Z*_p of order p-1=2q b = mpnew(0); while(1){ mprand(n, genrandom, alpha); mpmod(alpha, p, alpha); mpmul(alpha, alpha, b); mpmod(b, p, b); if(mpcmp(b, mpone) == 0) continue; mpexp(alpha, q, p, b); if(mpcmp(b, mpone) != 0) break; } mpfree(b); mpfree(q); } drawterm-20170818/libsec/genstrongprime.c000066400000000000000000000020171314554504700202730ustar00rootroot00000000000000#include "os.h" #include #include // Gordon's algorithm for generating a strong prime // Menezes et al () Handbook, p.150 void genstrongprime(mpint *p, int n, int accuracy) { mpint *s, *t, *r, *i; if(n < 64) n = 64; s = mpnew(n/2); genprime(s, (n/2)-16, accuracy); t = mpnew(n/2); genprime(t, n-mpsignif(s)-32, accuracy); // first r = 2it + 1 that's prime i = mpnew(16); r = mpnew(0); itomp(0x8000, i); mpleft(t, 1, t); // 2t mpmul(i, t, r); // 2it mpadd(r, mpone, r); // 2it + 1 for(;;){ if(probably_prime(r, 18)) break; mpadd(r, t, r); // r += 2t } // p0 = 2(s**(r-2) mod r)s - 1 itomp(2, p); mpsub(r, p, p); mpexp(s, p, r, p); mpmul(s, p, p); mpleft(p, 1, p); mpsub(p, mpone, p); // first p = p0 + 2irs that's prime itomp(0x8000, i); mpleft(r, 1, r); // 2r mpmul(r, s, r); // 2rs mpmul(r, i, i); // 2irs mpadd(p, i, p); // p0 + 2irs for(;;){ if(probably_prime(p, accuracy)) break; mpadd(p, r, p); // p += 2rs } mpfree(i); mpfree(s); mpfree(r); mpfree(t); } drawterm-20170818/libsec/hmac.c000066400000000000000000000022171314554504700161420ustar00rootroot00000000000000#include "os.h" #include /* rfc2104 */ static DigestState* hmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s, DigestState*(*x)(uchar*, ulong, uchar*, DigestState*), int xlen) { int i; uchar pad[65], innerdigest[256]; if(xlen > sizeof(innerdigest)) return nil; if(klen>64) return nil; /* first time through */ if(s == nil){ for(i=0; i<64; i++) pad[i] = 0x36; pad[64] = 0; for(i=0; i #include uchar key[] = "Jefe"; uchar data[] = "what do ya want for nothing?"; void main(void) { int i; uchar hash[MD5dlen]; hmac_md5(data, strlen((char*)data), key, 4, hash, nil); for(i=0; i /* * This MD4 is implemented from the description in Stinson's Cryptography, * theory and practice. -- presotto */ /* * Rotate ammounts used in the algorithm */ enum { S11= 3, S12= 7, S13= 11, S14= 19, S21= 3, S22= 5, S23= 9, S24= 13, S31= 3, S32= 9, S33= 11, S34= 15, }; typedef struct MD4Table MD4Table; struct MD4Table { uchar x; /* index into data block */ uchar rot; /* amount to rotate left by */ }; static MD4Table tab[] = { /* round 1 */ /*[0]*/ { 0, S11}, { 1, S12}, { 2, S13}, { 3, S14}, { 4, S11}, { 5, S12}, { 6, S13}, { 7, S14}, { 8, S11}, { 9, S12}, { 10, S13}, { 11, S14}, { 12, S11}, { 13, S12}, { 14, S13}, { 15, S14}, /* round 2 */ /*[16]*/{ 0, S21}, { 4, S22}, { 8, S23}, { 12, S24}, { 1, S21}, { 5, S22}, { 9, S23}, { 13, S24}, { 2, S21}, { 6, S22}, { 10, S23}, { 14, S24}, { 3, S21}, { 7, S22}, { 11, S23}, { 15, S24}, /* round 3 */ /*[32]*/{ 0, S31}, { 8, S32}, { 4, S33}, { 12, S34}, { 2, S31}, { 10, S32}, { 6, S33}, { 14, S34}, { 1, S31}, { 9, S32}, { 5, S33}, { 13, S34}, { 3, S31}, { 11, S32}, { 7, S33}, { 15, S34}, }; static void encode(uchar*, u32int*, ulong); static void decode(u32int*, uchar*, ulong); static void md4block(uchar *p, ulong len, MD4state *s) { int i; u32int a, b, c, d, tmp; MD4Table *t; uchar *end; u32int x[16]; for(end = p+len; p < end; p += 64){ a = s->state[0]; b = s->state[1]; c = s->state[2]; d = s->state[3]; decode(x, p, 64); for(i = 0; i < 48; i++){ t = tab + i; switch(i>>4){ case 0: a += (b & c) | (~b & d); break; case 1: a += ((b & c) | (b & d) | (c & d)) + 0x5A827999; break; case 2: a += (b ^ c ^ d) + 0x6ED9EBA1; break; } a += x[t->x]; a = (a << t->rot) | (a >> (32 - t->rot)); /* rotate variables */ tmp = d; d = c; c = b; b = a; a = tmp; } s->state[0] += a; s->state[1] += b; s->state[2] += c; s->state[3] += d; s->len += 64; } } MD4state* md4(uchar *p, ulong len, uchar *digest, MD4state *s) { u32int x[16]; uchar buf[128]; int i; uchar *e; if(s == nil){ s = malloc(sizeof(*s)); if(s == nil) return nil; memset(s, 0, sizeof(*s)); s->malloced = 1; } if(s->seeded == 0){ /* seed the state, these constants would look nicer big-endian */ s->state[0] = 0x67452301; s->state[1] = 0xefcdab89; s->state[2] = 0x98badcfe; s->state[3] = 0x10325476; s->seeded = 1; } /* fill out the partial 64 byte block from previous calls */ if(s->blen){ i = 64 - s->blen; if(len < i) i = len; memmove(s->buf + s->blen, p, i); len -= i; s->blen += i; p += i; if(s->blen == 64){ md4block(s->buf, s->blen, s); s->blen = 0; } } /* do 64 byte blocks */ i = len & ~0x3f; if(i){ md4block(p, i, s); len -= i; p += i; } /* save the left overs if not last call */ if(digest == 0){ if(len){ memmove(s->buf, p, len); s->blen += len; } return s; } /* * this is the last time through, pad what's left with 0x80, * 0's, and the input count to create a multiple of 64 bytes */ if(s->blen){ p = s->buf; len = s->blen; } else { memmove(buf, p, len); p = buf; } s->len += len; e = p + len; if(len < 56) i = 56 - len; else i = 120 - len; memset(e, 0, i); *e = 0x80; len += i; /* append the count */ x[0] = s->len<<3; x[1] = s->len>>29; encode(p+len, x, 8); /* digest the last part */ md4block(p, len+8, s); /* return result and free state */ encode(digest, s->state, MD4dlen); if(s->malloced == 1) free(s); return nil; } /* * encodes input (u32int) into output (uchar). Assumes len is * a multiple of 4. */ static void encode(uchar *output, u32int *input, ulong len) { u32int x; uchar *e; for(e = output + len; output < e;) { x = *input++; *output++ = x; *output++ = x >> 8; *output++ = x >> 16; *output++ = x >> 24; } } /* * decodes input (uchar) into output (u32int). Assumes len is * a multiple of 4. */ static void decode(u32int *output, uchar *input, ulong len) { uchar *e; for(e = input+len; input < e; input += 4) *output++ = input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24); } drawterm-20170818/libsec/md4test.c000066400000000000000000000010311314554504700166070ustar00rootroot00000000000000#include "os.h" #include #include char *tests[] = { "", "a", "abc", "message digest", "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 0 }; void main(void) { char **pp; uchar *p; int i; uchar digest[MD5dlen]; for(pp = tests; *pp; pp++){ p = (uchar*)*pp; md4(p, strlen(*pp), digest, 0); for(i = 0; i < MD5dlen; i++) print("%2.2ux", digest[i]); print("\n"); } } drawterm-20170818/libsec/md5.c000066400000000000000000000062661314554504700157270ustar00rootroot00000000000000#include "os.h" #include /* * rfc1321 requires that I include this. The code is new. The constants * all come from the rfc (hence the copyright). We trade a table for the * macros in rfc. The total size is a lot less. -- presotto * * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it * is identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided * that such works are identified as "derived from the RSA Data * Security, Inc. MD5 Message-Digest Algorithm" in all material * mentioning or referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software forany particular purpose. It is provided "as is" * without express or implied warranty of any kind. * These notices must be retained in any copies of any part of this * documentation and/or software. */ static void encode(uchar*, u32int*, ulong); extern void _md5block(uchar*, ulong, u32int*); MD5state* md5(uchar *p, ulong len, uchar *digest, MD5state *s) { u32int x[16]; uchar buf[128]; int i; uchar *e; if(s == nil){ s = malloc(sizeof(*s)); if(s == nil) return nil; memset(s, 0, sizeof(*s)); s->malloced = 1; } if(s->seeded == 0){ /* seed the state, these constants would look nicer big-endian */ s->state[0] = 0x67452301; s->state[1] = 0xefcdab89; s->state[2] = 0x98badcfe; s->state[3] = 0x10325476; s->seeded = 1; } /* fill out the partial 64 byte block from previous calls */ if(s->blen){ i = 64 - s->blen; if(len < i) i = len; memmove(s->buf + s->blen, p, i); len -= i; s->blen += i; p += i; if(s->blen == 64){ _md5block(s->buf, s->blen, s->state); s->len += s->blen; s->blen = 0; } } /* do 64 byte blocks */ i = len & ~0x3f; if(i){ _md5block(p, i, s->state); s->len += i; len -= i; p += i; } /* save the left overs if not last call */ if(digest == 0){ if(len){ memmove(s->buf, p, len); s->blen += len; } return s; } /* * this is the last time through, pad what's left with 0x80, * 0's, and the input count to create a multiple of 64 bytes */ if(s->blen){ p = s->buf; len = s->blen; } else { memmove(buf, p, len); p = buf; } s->len += len; e = p + len; if(len < 56) i = 56 - len; else i = 120 - len; memset(e, 0, i); *e = 0x80; len += i; /* append the count */ x[0] = s->len<<3; x[1] = s->len>>29; encode(p+len, x, 8); /* digest the last part */ _md5block(p, len+8, s->state); s->len += len; /* return result and free state */ encode(digest, s->state, MD5dlen); if(s->malloced == 1) free(s); return nil; } /* * encodes input (u32int) into output (uchar). Assumes len is * a multiple of 4. */ static void encode(uchar *output, u32int *input, ulong len) { u32int x; uchar *e; for(e = output + len; output < e;) { x = *input++; *output++ = x; *output++ = x >> 8; *output++ = x >> 16; *output++ = x >> 24; } } drawterm-20170818/libsec/md5block.c000066400000000000000000000116271314554504700167370ustar00rootroot00000000000000#include "os.h" #include /* * rfc1321 requires that I include this. The code is new. The constants * all come from the rfc (hence the copyright). We trade a table for the * macros in rfc. The total size is a lot less. -- presotto * * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it * is identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided * that such works are identified as "derived from the RSA Data * Security, Inc. MD5 Message-Digest Algorithm" in all material * mentioning or referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software forany particular purpose. It is provided "as is" * without express or implied warranty of any kind. * These notices must be retained in any copies of any part of this * documentation and/or software. */ /* * Rotate ammounts used in the algorithm */ enum { S11= 7, S12= 12, S13= 17, S14= 22, S21= 5, S22= 9, S23= 14, S24= 20, S31= 4, S32= 11, S33= 16, S34= 23, S41= 6, S42= 10, S43= 15, S44= 21, }; static u32int md5tab[] = { /* round 1 */ /*[0]*/ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, /* round 2 */ /*[16]*/0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, /* round 3 */ /*[32]*/0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, /* round 4 */ /*[48]*/0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; static void decode(u32int*, uchar*, ulong); extern void _md5block(uchar *p, ulong len, u32int *s); void _md5block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, sh; u32int *t; uchar *end; u32int x[16]; for(end = p+len; p < end; p += 64){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; decode(x, p, 64); t = md5tab; sh = 0; for(; sh != 16; t += 4){ a += ((c ^ d) & b) ^ d; a += x[sh] + t[0]; a = (a << S11) | (a >> (32 - S11)); a += b; d += ((b ^ c) & a) ^ c; d += x[sh + 1] + t[1]; d = (d << S12) | (d >> (32 - S12)); d += a; c += ((a ^ b) & d) ^ b; c += x[sh + 2] + t[2]; c = (c << S13) | (c >> (32 - S13)); c += d; b += ((d ^ a) & c) ^ a; b += x[sh + 3] + t[3]; b = (b << S14) | (b >> (32 - S14)); b += c; sh += 4; } sh = 1; for(; sh != 1+20*4; t += 4){ a += ((b ^ c) & d) ^ c; a += x[sh & 0xf] + t[0]; a = (a << S21) | (a >> (32 - S21)); a += b; d += ((a ^ b) & c) ^ b; d += x[(sh + 5) & 0xf] + t[1]; d = (d << S22) | (d >> (32 - S22)); d += a; c += ((d ^ a) & b) ^ a; c += x[(sh + 10) & 0xf] + t[2]; c = (c << S23) | (c >> (32 - S23)); c += d; b += ((c ^ d) & a) ^ d; b += x[(sh + 15) & 0xf] + t[3]; b = (b << S24) | (b >> (32 - S24)); b += c; sh += 20; } sh = 5; for(; sh != 5+12*4; t += 4){ a += b ^ c ^ d; a += x[sh & 0xf] + t[0]; a = (a << S31) | (a >> (32 - S31)); a += b; d += a ^ b ^ c; d += x[(sh + 3) & 0xf] + t[1]; d = (d << S32) | (d >> (32 - S32)); d += a; c += d ^ a ^ b; c += x[(sh + 6) & 0xf] + t[2]; c = (c << S33) | (c >> (32 - S33)); c += d; b += c ^ d ^ a; b += x[(sh + 9) & 0xf] + t[3]; b = (b << S34) | (b >> (32 - S34)); b += c; sh += 12; } sh = 0; for(; sh != 28*4; t += 4){ a += c ^ (b | ~d); a += x[sh & 0xf] + t[0]; a = (a << S41) | (a >> (32 - S41)); a += b; d += b ^ (a | ~c); d += x[(sh + 7) & 0xf] + t[1]; d = (d << S42) | (d >> (32 - S42)); d += a; c += a ^ (d | ~b); c += x[(sh + 14) & 0xf] + t[2]; c = (c << S43) | (c >> (32 - S43)); c += d; b += d ^ (c | ~a); b += x[(sh + 21) & 0xf] + t[3]; b = (b << S44) | (b >> (32 - S44)); b += c; sh += 28; } s[0] += a; s[1] += b; s[2] += c; s[3] += d; } } /* * decodes input (uchar) into output (u32int). Assumes len is * a multiple of 4. */ static void decode(u32int *output, uchar *input, ulong len) { uchar *e; for(e = input+len; input < e; input += 4) *output++ = input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24); } drawterm-20170818/libsec/md5pickle.c000066400000000000000000000012211314554504700171010ustar00rootroot00000000000000#include "os.h" #include char* md5pickle(MD5state *s) { char *p; int m, n; m = 4*9+4*((s->blen+3)/3); p = malloc(m); if(p == nil) return p; n = sprint(p, "%8.8ux %8.8ux %8.8ux %8.8ux ", s->state[0], s->state[1], s->state[2], s->state[3]); enc64(p+n, m-n, s->buf, s->blen); return p; } MD5state* md5unpickle(char *p) { MD5state *s; s = malloc(sizeof(*s)); if(s == nil) return nil; s->state[0] = strtoul(p, &p, 16); s->state[1] = strtoul(p, &p, 16); s->state[2] = strtoul(p, &p, 16); s->state[3] = strtoul(p, &p, 16); s->blen = dec64(s->buf, sizeof(s->buf), p, strlen(p)); s->malloced = 1; s->seeded = 1; return s; } drawterm-20170818/libsec/nfastrand.c000066400000000000000000000005071314554504700172120ustar00rootroot00000000000000#include #include #include #define Maxrand ((1UL<<31)-1) ulong nfastrand(ulong n) { ulong m, r; /* * set m to the maximum multiple of n <= 2^31-1 * so we want a random number < m. */ if(n > Maxrand) abort(); m = Maxrand - Maxrand % n; while((r = fastrand()) >= m) ; return r%n; } drawterm-20170818/libsec/os.h000066400000000000000000000000411314554504700156510ustar00rootroot00000000000000#include #include drawterm-20170818/libsec/primetest.c000066400000000000000000000046661314554504700172600ustar00rootroot00000000000000#include "os.h" #include #include void main(void) { mpint *z = mpnew(0); mpint *p = mpnew(0); mpint *q = mpnew(0); mpint *nine = mpnew(0); fmtinstall('B', mpconv); strtomp("2492491", nil, 16, z); // 38347921 = x*y = (2**28-9)/7, // an example of 3**(n-1)=1 mod n strtomp("15662C00E811", nil, 16, p);// 23528569104401, a prime uitomp(9, nine); if(probably_prime(z, 5) == 1) fprint(2, "tricked primality test\n"); if(probably_prime(nine, 5) == 1) fprint(2, "9 passed primality test!\n"); if(probably_prime(p, 25) == 1) fprint(2, "ok\n"); DSAprimes(q, p, nil); print("q=%B\np=%B\n", q, p); exits(0); } // example output, checked with Maple: // seed EB7B6E35F7CD37B511D96C67D6688CC4DD440E1E // q=E0F0EF284E10796C5A2A511E94748BA03C795C13 // = 1284186945063585093695748280224501481698995297299 // p=C41CFBE4D4846F67A3DF7DE9921A49D3B42DC33728427AB159CEC8CBBDB12B5F0C244F1A734AEB9840804EA3C25036AD1B61AFF3ABBC247CD4B384224567A863A6F020E7EE9795554BCD08ABAD7321AF27E1E92E3DB1C6E7E94FAAE590AE9C48F96D93D178E809401ABE8A534A1EC44359733475A36A70C7B425125062B1142D // = 137715385439333164327584575331308277462546592976152006175830654712456008630139443747529133857837818585400418619916530061955288983751958831927807888408309879880101870216437711393638413509484569804814373511469405934988856674935304074081350525593807908358867354528898618574659752879015380013845760006721861915693 // r=DF310F4E54A5FEC5D86D3E14863921E834113E060F90052AD332B3241CEF2497EFA0303D6344F7C819691A0F9C4A773815AF8EAECFB7EC1D98F039F17A32A7E887D97251A927D093F44A55577F4D70444AEBD06B9B45695EC23962B175F266895C67D21C4656848614D888A4 // = 107239359478548771267308764204625458348785444483302647285245969203446101233421655396874997253111222983406676955642093641709149748793954493558324738441197139556917622937892491175016280660608595599724194374948056515856812347094848443460715881455884639869144172708 // g=2F1C308DC46B9A44B52DF7DACCE1208CCEF72F69C743ADD4D2327173444ED6E65E074694246E07F9FD4AE26E0FDDD9F54F813C40CB9BCD4338EA6F242AB94CD410E676C290368A16B1A3594877437E516C53A6EEE5493A038A017E955E218E7819734E3E2A6E0BAE08B14258F8C03CC1B30E0DDADFCF7CEDF0727684D3D255F1 // = 33081848392740465806285326014906437543653045153885419334085917570615301913274531387168723847139029827598735376746057461417880810924280288611116213062512408829164220104555543445909528701551198146080221790002337033997295756585193926863581671466708482411159477816144226847280417522524922667065714073338662508017 drawterm-20170818/libsec/prng.c000066400000000000000000000002731314554504700162000ustar00rootroot00000000000000#include "os.h" #include #include // // just use the libc prng to fill a buffer // void prng(uchar *p, int n) { uchar *e; for(e = p+n; p < e; p++) *p = rand(); } drawterm-20170818/libsec/probably_prime.c000066400000000000000000000030371314554504700202410ustar00rootroot00000000000000#include "os.h" #include #include // Miller-Rabin probabilistic primality testing // Knuth (1981) Seminumerical Algorithms, p.379 // Menezes et al () Handbook, p.39 // 0 if composite; 1 if almost surely prime, Pr(err)<1/4**nrep int probably_prime(mpint *n, int nrep) { int j, k, rep, nbits, isprime = 1; mpint *nm1, *q, *x, *y, *r; if(n->sign < 0) sysfatal("negative prime candidate"); if(nrep <= 0) nrep = 18; k = mptoi(n); if(k == 2) // 2 is prime return 1; if(k < 2) // 1 is not prime return 0; if((n->p[0] & 1) == 0) // even is not prime return 0; // test against small prime numbers if(smallprimetest(n) < 0) return 0; // fermat test, 2^n mod n == 2 if p is prime x = uitomp(2, nil); y = mpnew(0); mpexp(x, n, n, y); k = mptoi(y); if(k != 2){ mpfree(x); mpfree(y); return 0; } nbits = mpsignif(n); nm1 = mpnew(nbits); mpsub(n, mpone, nm1); // nm1 = n - 1 */ k = mplowbits0(nm1); q = mpnew(0); mpright(nm1, k, q); // q = (n-1)/2**k for(rep = 0; rep < nrep; rep++){ // x = random in [2, n-2] r = mprand(nbits, prng, nil); mpmod(r, nm1, x); mpfree(r); if(mpcmp(x, mpone) <= 0) continue; // y = x**q mod n mpexp(x, q, n, y); if(mpcmp(y, mpone) == 0 || mpcmp(y, nm1) == 0) goto done; for(j = 1; j < k; j++){ mpmul(y, y, x); mpmod(x, n, y); // y = y*y mod n if(mpcmp(y, nm1) == 0) goto done; if(mpcmp(y, mpone) == 0){ isprime = 0; goto done; } } isprime = 0; } done: mpfree(y); mpfree(x); mpfree(q); mpfree(nm1); return isprime; } drawterm-20170818/libsec/rc4.c000066400000000000000000000026071314554504700157250ustar00rootroot00000000000000#include "os.h" #include void setupRC4state(RC4state *key, uchar *start, int n) { int t; int index2; uchar *state; uchar *p, *e, *sp, *se; state = key->state; se = &state[256]; for(sp = state; sp < se; sp++) *sp = sp - state; key->x = 0; key->y = 0; index2 = 0; e = start + n; p = start; for(sp = state; sp < se; sp++) { t = *sp; index2 = (*p + t + index2) & 255; *sp = state[index2]; state[index2] = t; if(++p >= e) p = start; } } void rc4(RC4state *key, uchar *p, int len) { int tx, ty; int x, y; uchar *state; uchar *e; x = key->x; y = key->y; state = &key->state[0]; for(e = p + len; p < e; p++) { x = (x+1)&255; tx = state[x]; y = (y+tx)&255; ty = state[y]; state[x] = ty; state[y] = tx; *p ^= state[(tx+ty)&255]; } key->x = x; key->y = y; } void rc4skip(RC4state *key, int len) { int tx, ty; int x, y; uchar *state; int i; x = key->x; y = key->y; state = &key->state[0]; for(i=0; ix = x; key->y = y; } void rc4back(RC4state *key, int len) { int tx, ty; int x, y; uchar *state; int i; x = key->x; y = key->y; state = &key->state[0]; for(i=0; ix = x; key->y = y; } drawterm-20170818/libsec/readcert.c000066400000000000000000000013671314554504700170300ustar00rootroot00000000000000#include #include #include #include static char* readfile(char *name) { int fd; char *s; Dir *d; fd = open(name, OREAD); if(fd < 0) return nil; if((d = dirfstat(fd)) == nil) return nil; s = malloc(d->length + 1); if(s == nil || readn(fd, s, d->length) != d->length){ free(s); free(d); close(fd); return nil; } close(fd); s[d->length] = '\0'; free(d); return s; } uchar* readcert(char *filename, int *pcertlen) { char *pem; uchar *binary; pem = readfile(filename); if(pem == nil){ werrstr("can't read %s", filename); return nil; } binary = decodepem(pem, "CERTIFICATE", pcertlen); free(pem); if(binary == nil){ werrstr("can't parse %s", filename); return nil; } return binary; } drawterm-20170818/libsec/rsaalloc.c000066400000000000000000000012211314554504700170240ustar00rootroot00000000000000#include "os.h" #include #include RSApub* rsapuballoc(void) { RSApub *rsa; rsa = mallocz(sizeof(*rsa), 1); if(rsa == nil) sysfatal("rsapuballoc"); return rsa; } void rsapubfree(RSApub *rsa) { if(rsa == nil) return; mpfree(rsa->ek); mpfree(rsa->n); free(rsa); } RSApriv* rsaprivalloc(void) { RSApriv *rsa; rsa = mallocz(sizeof(*rsa), 1); if(rsa == nil) sysfatal("rsaprivalloc"); return rsa; } void rsaprivfree(RSApriv *rsa) { if(rsa == nil) return; mpfree(rsa->pub.ek); mpfree(rsa->pub.n); mpfree(rsa->dk); mpfree(rsa->p); mpfree(rsa->q); mpfree(rsa->kp); mpfree(rsa->kq); mpfree(rsa->c2); free(rsa); } drawterm-20170818/libsec/rsadecrypt.c000066400000000000000000000013551314554504700174140ustar00rootroot00000000000000#include "os.h" #include #include // decrypt rsa using garner's algorithm for the chinese remainder theorem // seminumerical algorithms, knuth, pp 253-254 // applied cryptography, menezes et al, pg 612 mpint* rsadecrypt(RSApriv *rsa, mpint *in, mpint *out) { mpint *v1, *v2; if(out == nil) out = mpnew(0); // convert in to modular representation v1 = mpnew(0); mpmod(in, rsa->p, v1); v2 = mpnew(0); mpmod(in, rsa->q, v2); // exponentiate the modular rep mpexp(v1, rsa->kp, rsa->p, v1); mpexp(v2, rsa->kq, rsa->q, v2); // out = v1 + p*((v2-v1)*c2 mod q) mpsub(v2, v1, v2); mpmul(v2, rsa->c2, v2); mpmod(v2, rsa->q, v2); mpmul(v2, rsa->p, out); mpadd(v1, out, out); mpfree(v1); mpfree(v2); return out; } drawterm-20170818/libsec/rsaencrypt.c000066400000000000000000000003001314554504700174130ustar00rootroot00000000000000#include "os.h" #include #include mpint* rsaencrypt(RSApub *rsa, mpint *in, mpint *out) { if(out == nil) out = mpnew(0); mpexp(in, rsa->ek, rsa->n, out); return out; } drawterm-20170818/libsec/rsafill.c000066400000000000000000000021201314554504700166570ustar00rootroot00000000000000#include "os.h" #include #include RSApriv* rsafill(mpint *n, mpint *e, mpint *d, mpint *p, mpint *q) { mpint *c2, *kq, *kp, *x; RSApriv *rsa; // make sure we're not being hoodwinked if(!probably_prime(p, 10) || !probably_prime(q, 10)){ werrstr("rsafill: p or q not prime"); return nil; } x = mpnew(0); mpmul(p, q, x); if(mpcmp(n, x) != 0){ werrstr("rsafill: n != p*q"); mpfree(x); return nil; } c2 = mpnew(0); mpsub(p, mpone, c2); mpsub(q, mpone, x); mpmul(c2, x, x); mpmul(e, d, c2); mpmod(c2, x, x); if(mpcmp(x, mpone) != 0){ werrstr("rsafill: e*d != 1 mod (p-1)*(q-1)"); mpfree(x); mpfree(c2); return nil; } // compute chinese remainder coefficient mpinvert(p, q, c2); // for crt a**k mod p == (a**(k mod p-1)) mod p kq = mpnew(0); kp = mpnew(0); mpsub(p, mpone, x); mpmod(d, x, kp); mpsub(q, mpone, x); mpmod(d, x, kq); rsa = rsaprivalloc(); rsa->pub.ek = mpcopy(e); rsa->pub.n = mpcopy(n); rsa->dk = mpcopy(d); rsa->kp = kp; rsa->kq = kq; rsa->p = mpcopy(p); rsa->q = mpcopy(q); rsa->c2 = c2; mpfree(x); return rsa; } drawterm-20170818/libsec/rsagen.c000066400000000000000000000026531314554504700165150ustar00rootroot00000000000000#include "os.h" #include #include static void genrand(mpint *p, int n) { mpdigit x; // generate n random bits with high set mpbits(p, n); genrandom((uchar*)p->p, (n+7)/8); p->top = (n+Dbits-1)/Dbits; x = 1; x <<= ((n-1)%Dbits); p->p[p->top-1] &= (x-1); p->p[p->top-1] |= x; } RSApriv* rsagen(int nlen, int elen, int rounds) { mpint *p, *q, *e, *d, *phi, *n, *t1, *t2, *kp, *kq, *c2; RSApriv *rsa; p = mpnew(nlen/2); q = mpnew(nlen/2); n = mpnew(nlen); e = mpnew(elen); d = mpnew(0); phi = mpnew(nlen); // create the prime factors and euclid's function genstrongprime(p, nlen/2, rounds); genstrongprime(q, nlen - mpsignif(p) + 1, rounds); mpmul(p, q, n); mpsub(p, mpone, e); mpsub(q, mpone, d); mpmul(e, d, phi); // find an e relatively prime to phi t1 = mpnew(0); t2 = mpnew(0); genrand(e, elen); for(;;){ mpextendedgcd(e, phi, d, t1, t2); if(mpcmp(d, mpone) == 0) break; mpadd(mpone, e, e); } mpfree(t1); mpfree(t2); // d = e**-1 mod phi mpinvert(e, phi, d); // compute chinese remainder coefficient c2 = mpnew(0); mpinvert(p, q, c2); // for crt a**k mod p == (a**(k mod p-1)) mod p kq = mpnew(0); kp = mpnew(0); mpsub(p, mpone, phi); mpmod(d, phi, kp); mpsub(q, mpone, phi); mpmod(d, phi, kq); rsa = rsaprivalloc(); rsa->pub.ek = e; rsa->pub.n = n; rsa->dk = d; rsa->kp = kp; rsa->kq = kq; rsa->p = p; rsa->q = q; rsa->c2 = c2; mpfree(phi); return rsa; } drawterm-20170818/libsec/rsaprivtopub.c000066400000000000000000000003551314554504700177730ustar00rootroot00000000000000#include "os.h" #include #include RSApub* rsaprivtopub(RSApriv *priv) { RSApub *pub; pub = rsapuballoc(); if(pub == nil) return nil; pub->n = mpcopy(priv->pub.n); pub->ek = mpcopy(priv->pub.ek); return pub; } drawterm-20170818/libsec/rsatest.c000066400000000000000000000021071314554504700167150ustar00rootroot00000000000000#include "os.h" #include #include #include void main(void) { RSApriv *rsa; Biobuf b; char *p; int n; mpint *clr, *enc, *clr2; uchar buf[4096]; uchar *e; vlong start; fmtinstall('B', mpconv); rsa = rsagen(1024, 16, 0); if(rsa == nil) sysfatal("rsagen"); Binit(&b, 0, OREAD); clr = mpnew(0); clr2 = mpnew(0); enc = mpnew(0); strtomp("123456789abcdef123456789abcdef123456789abcdef123456789abcdef", nil, 16, clr); rsaencrypt(&rsa->pub, clr, enc); start = nsec(); for(n = 0; n < 10; n++) rsadecrypt(rsa, enc, clr); print("%lld\n", nsec()-start); start = nsec(); for(n = 0; n < 10; n++) mpexp(enc, rsa->dk, rsa->pub.n, clr2); print("%lld\n", nsec()-start); if(mpcmp(clr, clr2) != 0) print("%B != %B\n", clr, clr2); print("> "); while(p = Brdline(&b, '\n')){ n = Blinelen(&b); letomp((uchar*)p, n, clr); print("clr %B\n", clr); rsaencrypt(&rsa->pub, clr, enc); print("enc %B\n", enc); rsadecrypt(rsa, enc, clr); print("clr %B\n", clr); n = mptole(clr, buf, sizeof(buf), nil); write(1, buf, n); print("> "); } } drawterm-20170818/libsec/sha1.c000066400000000000000000000043471314554504700160740ustar00rootroot00000000000000#include "os.h" #include static void encode(uchar*, u32int*, ulong); extern void _sha1block(uchar*, ulong, u32int*); /* * we require len to be a multiple of 64 for all but * the last call. There must be room in the input buffer * to pad. */ SHA1state* sha1(uchar *p, ulong len, uchar *digest, SHA1state *s) { uchar buf[128]; u32int x[16]; int i; uchar *e; if(s == nil){ s = malloc(sizeof(*s)); if(s == nil) return nil; memset(s, 0, sizeof(*s)); s->malloced = 1; } if(s->seeded == 0){ /* seed the state, these constants would look nicer big-endian */ s->state[0] = 0x67452301; s->state[1] = 0xefcdab89; s->state[2] = 0x98badcfe; s->state[3] = 0x10325476; s->state[4] = 0xc3d2e1f0; s->seeded = 1; } /* fill out the partial 64 byte block from previous calls */ if(s->blen){ i = 64 - s->blen; if(len < i) i = len; memmove(s->buf + s->blen, p, i); len -= i; s->blen += i; p += i; if(s->blen == 64){ _sha1block(s->buf, s->blen, s->state); s->len += s->blen; s->blen = 0; } } /* do 64 byte blocks */ i = len & ~0x3f; if(i){ _sha1block(p, i, s->state); s->len += i; len -= i; p += i; } /* save the left overs if not last call */ if(digest == 0){ if(len){ memmove(s->buf, p, len); s->blen += len; } return s; } /* * this is the last time through, pad what's left with 0x80, * 0's, and the input count to create a multiple of 64 bytes */ if(s->blen){ p = s->buf; len = s->blen; } else { memmove(buf, p, len); p = buf; } s->len += len; e = p + len; if(len < 56) i = 56 - len; else i = 120 - len; memset(e, 0, i); *e = 0x80; len += i; /* append the count */ x[0] = s->len>>29; x[1] = s->len<<3; encode(p+len, x, 8); /* digest the last part */ _sha1block(p, len+8, s->state); s->len += len+8; /* return result and free state */ encode(digest, s->state, SHA1dlen); if(s->malloced == 1) free(s); return nil; } /* * encodes input (ulong) into output (uchar). Assumes len is * a multiple of 4. */ static void encode(uchar *output, u32int *input, ulong len) { u32int x; uchar *e; for(e = output + len; output < e;) { x = *input++; *output++ = x >> 24; *output++ = x >> 16; *output++ = x >> 8; *output++ = x; } } drawterm-20170818/libsec/sha1block.c000066400000000000000000000111011314554504700170710ustar00rootroot00000000000000#include "os.h" void _sha1block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, e, x; uchar *end; u32int *wp, *wend; u32int w[80]; /* at this point, we have a multiple of 64 bytes */ for(end = p+len; p < end;){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; e = s[4]; wend = w + 15; for(wp = w; wp < wend; wp += 5){ wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); wp[1] = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7]; d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); wp[2] = (p[8]<<24) | (p[9]<<16) | (p[10]<<8) | p[11]; c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); wp[3] = (p[12]<<24) | (p[13]<<16) | (p[14]<<8) | p[15]; b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); wp[4] = (p[16]<<24) | (p[17]<<16) | (p[18]<<8) | p[19]; a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); p += 20; } wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); wp += 5; p += 4; wend = w + 40; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x6ed9eba1 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x6ed9eba1 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x6ed9eba1 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x6ed9eba1 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x6ed9eba1 + (c^d^e); c = (c<<30)|(c>>2); } wend = w + 60; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x8f1bbcdc + ((b&c)|((b|c)&d)); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x8f1bbcdc + ((a&b)|((a|b)&c)); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x8f1bbcdc + ((e&a)|((e|a)&b)); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x8f1bbcdc + ((d&e)|((d|e)&a)); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x8f1bbcdc + ((c&d)|((c|d)&e)); c = (c<<30)|(c>>2); } wend = w + 80; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0xca62c1d6 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0xca62c1d6 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0xca62c1d6 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0xca62c1d6 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0xca62c1d6 + (c^d^e); c = (c<<30)|(c>>2); } /* save state */ s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; } } drawterm-20170818/libsec/sha1pickle.c000066400000000000000000000013151314554504700172540ustar00rootroot00000000000000#include "os.h" #include char* sha1pickle(SHA1state *s) { char *p; int m, n; m = 5*9+4*((s->blen+3)/3); p = malloc(m); if(p == nil) return p; n = sprint(p, "%8.8ux %8.8ux %8.8ux %8.8ux %8.8ux ", s->state[0], s->state[1], s->state[2], s->state[3], s->state[4]); enc64(p+n, m-n, s->buf, s->blen); return p; } SHA1state* sha1unpickle(char *p) { SHA1state *s; s = malloc(sizeof(*s)); if(s == nil) return nil; s->state[0] = strtoul(p, &p, 16); s->state[1] = strtoul(p, &p, 16); s->state[2] = strtoul(p, &p, 16); s->state[3] = strtoul(p, &p, 16); s->state[4] = strtoul(p, &p, 16); s->blen = dec64(s->buf, sizeof(s->buf), p, strlen(p)); s->malloced = 1; s->seeded = 1; return s; } drawterm-20170818/libsec/smallprimes.c000066400000000000000000000153031314554504700175620ustar00rootroot00000000000000#include "os.h" ulong smallprimes[1000] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, }; drawterm-20170818/libsec/smallprimetest.c000066400000000000000000002117601314554504700203040ustar00rootroot00000000000000#include "os.h" #include #include static ulong smallprimes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, 18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, 18517, 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, 18701, 18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, 19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, 19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, 19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, 19603, 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, 20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, 20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809, 20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, 20983, 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, 21139, 21143, 21149, 21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, 21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, 21841, 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, 22003, 22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, 22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, 22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, 22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, 22871, 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, 23029, 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, 23167, 23173, 23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, 23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, 23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043, 24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, 24169, 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, 24371, 24373, 24379, 24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, 25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, 25183, 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, 25343, 25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, 25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, 25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, 25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, 26249, 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, 26399, 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, 26561, 26573, 26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, 26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, 27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487, 27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, 27691, 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, 27799, 27803, 27809, 27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, 28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, 28579, 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, 28687, 28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, 29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, 29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, 29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, 29611, 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, 29819, 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, 29989, 30011, 30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, 30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, 30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931, 30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, 31091, 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, 31231, 31237, 31247, 31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, 31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, 32063, 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, 32203, 32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, 32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, 32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, 32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, 33053, 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, 33211, 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, 33377, 33391, 33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, 33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, 33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297, 34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, 34457, 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, 34591, 34603, 34607, 34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, 35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, 35401, 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, 35537, 35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, 35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, 36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, 36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, 36541, 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, 36691, 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, 36821, 36833, 36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, 37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, 37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717, 37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, 37951, 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, 38119, 38149, 38153, 38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, 38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, 38921, 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, 39097, 39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, 39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, 39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, 39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, 40009, 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, 40169, 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, 40361, 40387, 40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, 40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, 41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299, 41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, 41507, 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, 41627, 41641, 41647, 41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, 42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, 42379, 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, 42487, 42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, 42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, 42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, 43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, 43499, 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, 43661, 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, 43853, 43867, 43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, 44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, 44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777, 44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, 44953, 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, 45131, 45137, 45139, 45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, 45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, 45979, 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, 46153, 46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, 46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, 46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, 46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, 47143, 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, 47317, 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, 47497, 47501, 47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, 47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, 48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463, 48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, 48611, 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, 48779, 48781, 48787, 48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, 49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, 49537, 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, 49711, 49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, 50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, 50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, 50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, 50651, 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, 50867, 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, 51043, 51047, 51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, 51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, 51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941, 51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, 52127, 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, 52289, 52291, 52301, 52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, 52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, 53117, 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, 53279, 53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, 53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, 53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, 53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, 54311, 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, 54443, 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, 54581, 54583, 54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, 54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, 55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631, 55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, 55793, 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, 55903, 55921, 55927, 55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, 56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, 56711, 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, 56857, 56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, 57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, 57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, 57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, 57787, 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, 57947, 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, 58111, 58129, 58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, 58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, 58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083, 59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, 59233, 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, 59399, 59407, 59417, 59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, 60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, 60251, 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, 60427, 60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, 60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, 60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, 61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, 61483, 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, 61631, 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, 61781, 61813, 61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, 62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, 62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827, 62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, 62989, 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, 63199, 63211, 63241, 63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, 63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, 63929, 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, 64151, 64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, 64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, 64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, 64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, 65179, 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, 65381, 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, 65519, 65521, 65537, 65539, 65543, 65551, 65557, 65563, 65579, 65581, 65587, 65599, 65609, 65617, 65629, 65633, 65647, 65651, 65657, 65677, 65687, 65699, 65701, 65707, 65713, 65717, 65719, 65729, 65731, 65761, 65777, 65789, 65809, 65827, 65831, 65837, 65839, 65843, 65851, 65867, 65881, 65899, 65921, 65927, 65929, 65951, 65957, 65963, 65981, 65983, 65993, 66029, 66037, 66041, 66047, 66067, 66071, 66083, 66089, 66103, 66107, 66109, 66137, 66161, 66169, 66173, 66179, 66191, 66221, 66239, 66271, 66293, 66301, 66337, 66343, 66347, 66359, 66361, 66373, 66377, 66383, 66403, 66413, 66431, 66449, 66457, 66463, 66467, 66491, 66499, 66509, 66523, 66529, 66533, 66541, 66553, 66569, 66571, 66587, 66593, 66601, 66617, 66629, 66643, 66653, 66683, 66697, 66701, 66713, 66721, 66733, 66739, 66749, 66751, 66763, 66791, 66797, 66809, 66821, 66841, 66851, 66853, 66863, 66877, 66883, 66889, 66919, 66923, 66931, 66943, 66947, 66949, 66959, 66973, 66977, 67003, 67021, 67033, 67043, 67049, 67057, 67061, 67073, 67079, 67103, 67121, 67129, 67139, 67141, 67153, 67157, 67169, 67181, 67187, 67189, 67211, 67213, 67217, 67219, 67231, 67247, 67261, 67271, 67273, 67289, 67307, 67339, 67343, 67349, 67369, 67391, 67399, 67409, 67411, 67421, 67427, 67429, 67433, 67447, 67453, 67477, 67481, 67489, 67493, 67499, 67511, 67523, 67531, 67537, 67547, 67559, 67567, 67577, 67579, 67589, 67601, 67607, 67619, 67631, 67651, 67679, 67699, 67709, 67723, 67733, 67741, 67751, 67757, 67759, 67763, 67777, 67783, 67789, 67801, 67807, 67819, 67829, 67843, 67853, 67867, 67883, 67891, 67901, 67927, 67931, 67933, 67939, 67943, 67957, 67961, 67967, 67979, 67987, 67993, 68023, 68041, 68053, 68059, 68071, 68087, 68099, 68111, 68113, 68141, 68147, 68161, 68171, 68207, 68209, 68213, 68219, 68227, 68239, 68261, 68279, 68281, 68311, 68329, 68351, 68371, 68389, 68399, 68437, 68443, 68447, 68449, 68473, 68477, 68483, 68489, 68491, 68501, 68507, 68521, 68531, 68539, 68543, 68567, 68581, 68597, 68611, 68633, 68639, 68659, 68669, 68683, 68687, 68699, 68711, 68713, 68729, 68737, 68743, 68749, 68767, 68771, 68777, 68791, 68813, 68819, 68821, 68863, 68879, 68881, 68891, 68897, 68899, 68903, 68909, 68917, 68927, 68947, 68963, 68993, 69001, 69011, 69019, 69029, 69031, 69061, 69067, 69073, 69109, 69119, 69127, 69143, 69149, 69151, 69163, 69191, 69193, 69197, 69203, 69221, 69233, 69239, 69247, 69257, 69259, 69263, 69313, 69317, 69337, 69341, 69371, 69379, 69383, 69389, 69401, 69403, 69427, 69431, 69439, 69457, 69463, 69467, 69473, 69481, 69491, 69493, 69497, 69499, 69539, 69557, 69593, 69623, 69653, 69661, 69677, 69691, 69697, 69709, 69737, 69739, 69761, 69763, 69767, 69779, 69809, 69821, 69827, 69829, 69833, 69847, 69857, 69859, 69877, 69899, 69911, 69929, 69931, 69941, 69959, 69991, 69997, 70001, 70003, 70009, 70019, 70039, 70051, 70061, 70067, 70079, 70099, 70111, 70117, 70121, 70123, 70139, 70141, 70157, 70163, 70177, 70181, 70183, 70199, 70201, 70207, 70223, 70229, 70237, 70241, 70249, 70271, 70289, 70297, 70309, 70313, 70321, 70327, 70351, 70373, 70379, 70381, 70393, 70423, 70429, 70439, 70451, 70457, 70459, 70481, 70487, 70489, 70501, 70507, 70529, 70537, 70549, 70571, 70573, 70583, 70589, 70607, 70619, 70621, 70627, 70639, 70657, 70663, 70667, 70687, 70709, 70717, 70729, 70753, 70769, 70783, 70793, 70823, 70841, 70843, 70849, 70853, 70867, 70877, 70879, 70891, 70901, 70913, 70919, 70921, 70937, 70949, 70951, 70957, 70969, 70979, 70981, 70991, 70997, 70999, 71011, 71023, 71039, 71059, 71069, 71081, 71089, 71119, 71129, 71143, 71147, 71153, 71161, 71167, 71171, 71191, 71209, 71233, 71237, 71249, 71257, 71261, 71263, 71287, 71293, 71317, 71327, 71329, 71333, 71339, 71341, 71347, 71353, 71359, 71363, 71387, 71389, 71399, 71411, 71413, 71419, 71429, 71437, 71443, 71453, 71471, 71473, 71479, 71483, 71503, 71527, 71537, 71549, 71551, 71563, 71569, 71593, 71597, 71633, 71647, 71663, 71671, 71693, 71699, 71707, 71711, 71713, 71719, 71741, 71761, 71777, 71789, 71807, 71809, 71821, 71837, 71843, 71849, 71861, 71867, 71879, 71881, 71887, 71899, 71909, 71917, 71933, 71941, 71947, 71963, 71971, 71983, 71987, 71993, 71999, 72019, 72031, 72043, 72047, 72053, 72073, 72077, 72089, 72091, 72101, 72103, 72109, 72139, 72161, 72167, 72169, 72173, 72211, 72221, 72223, 72227, 72229, 72251, 72253, 72269, 72271, 72277, 72287, 72307, 72313, 72337, 72341, 72353, 72367, 72379, 72383, 72421, 72431, 72461, 72467, 72469, 72481, 72493, 72497, 72503, 72533, 72547, 72551, 72559, 72577, 72613, 72617, 72623, 72643, 72647, 72649, 72661, 72671, 72673, 72679, 72689, 72701, 72707, 72719, 72727, 72733, 72739, 72763, 72767, 72797, 72817, 72823, 72859, 72869, 72871, 72883, 72889, 72893, 72901, 72907, 72911, 72923, 72931, 72937, 72949, 72953, 72959, 72973, 72977, 72997, 73009, 73013, 73019, 73037, 73039, 73043, 73061, 73063, 73079, 73091, 73121, 73127, 73133, 73141, 73181, 73189, 73237, 73243, 73259, 73277, 73291, 73303, 73309, 73327, 73331, 73351, 73361, 73363, 73369, 73379, 73387, 73417, 73421, 73433, 73453, 73459, 73471, 73477, 73483, 73517, 73523, 73529, 73547, 73553, 73561, 73571, 73583, 73589, 73597, 73607, 73609, 73613, 73637, 73643, 73651, 73673, 73679, 73681, 73693, 73699, 73709, 73721, 73727, 73751, 73757, 73771, 73783, 73819, 73823, 73847, 73849, 73859, 73867, 73877, 73883, 73897, 73907, 73939, 73943, 73951, 73961, 73973, 73999, 74017, 74021, 74027, 74047, 74051, 74071, 74077, 74093, 74099, 74101, 74131, 74143, 74149, 74159, 74161, 74167, 74177, 74189, 74197, 74201, 74203, 74209, 74219, 74231, 74257, 74279, 74287, 74293, 74297, 74311, 74317, 74323, 74353, 74357, 74363, 74377, 74381, 74383, 74411, 74413, 74419, 74441, 74449, 74453, 74471, 74489, 74507, 74509, 74521, 74527, 74531, 74551, 74561, 74567, 74573, 74587, 74597, 74609, 74611, 74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719, 74729, 74731, 74747, 74759, 74761, 74771, 74779, 74797, 74821, 74827, 74831, 74843, 74857, 74861, 74869, 74873, 74887, 74891, 74897, 74903, 74923, 74929, 74933, 74941, 74959, 75011, 75013, 75017, 75029, 75037, 75041, 75079, 75083, 75109, 75133, 75149, 75161, 75167, 75169, 75181, 75193, 75209, 75211, 75217, 75223, 75227, 75239, 75253, 75269, 75277, 75289, 75307, 75323, 75329, 75337, 75347, 75353, 75367, 75377, 75389, 75391, 75401, 75403, 75407, 75431, 75437, 75479, 75503, 75511, 75521, 75527, 75533, 75539, 75541, 75553, 75557, 75571, 75577, 75583, 75611, 75617, 75619, 75629, 75641, 75653, 75659, 75679, 75683, 75689, 75703, 75707, 75709, 75721, 75731, 75743, 75767, 75773, 75781, 75787, 75793, 75797, 75821, 75833, 75853, 75869, 75883, 75913, 75931, 75937, 75941, 75967, 75979, 75983, 75989, 75991, 75997, 76001, 76003, 76031, 76039, 76079, 76081, 76091, 76099, 76103, 76123, 76129, 76147, 76157, 76159, 76163, 76207, 76213, 76231, 76243, 76249, 76253, 76259, 76261, 76283, 76289, 76303, 76333, 76343, 76367, 76369, 76379, 76387, 76403, 76421, 76423, 76441, 76463, 76471, 76481, 76487, 76493, 76507, 76511, 76519, 76537, 76541, 76543, 76561, 76579, 76597, 76603, 76607, 76631, 76649, 76651, 76667, 76673, 76679, 76697, 76717, 76733, 76753, 76757, 76771, 76777, 76781, 76801, 76819, 76829, 76831, 76837, 76847, 76871, 76873, 76883, 76907, 76913, 76919, 76943, 76949, 76961, 76963, 76991, 77003, 77017, 77023, 77029, 77041, 77047, 77069, 77081, 77093, 77101, 77137, 77141, 77153, 77167, 77171, 77191, 77201, 77213, 77237, 77239, 77243, 77249, 77261, 77263, 77267, 77269, 77279, 77291, 77317, 77323, 77339, 77347, 77351, 77359, 77369, 77377, 77383, 77417, 77419, 77431, 77447, 77471, 77477, 77479, 77489, 77491, 77509, 77513, 77521, 77527, 77543, 77549, 77551, 77557, 77563, 77569, 77573, 77587, 77591, 77611, 77617, 77621, 77641, 77647, 77659, 77681, 77687, 77689, 77699, 77711, 77713, 77719, 77723, 77731, 77743, 77747, 77761, 77773, 77783, 77797, 77801, 77813, 77839, 77849, 77863, 77867, 77893, 77899, 77929, 77933, 77951, 77969, 77977, 77983, 77999, 78007, 78017, 78031, 78041, 78049, 78059, 78079, 78101, 78121, 78137, 78139, 78157, 78163, 78167, 78173, 78179, 78191, 78193, 78203, 78229, 78233, 78241, 78259, 78277, 78283, 78301, 78307, 78311, 78317, 78341, 78347, 78367, 78401, 78427, 78437, 78439, 78467, 78479, 78487, 78497, 78509, 78511, 78517, 78539, 78541, 78553, 78569, 78571, 78577, 78583, 78593, 78607, 78623, 78643, 78649, 78653, 78691, 78697, 78707, 78713, 78721, 78737, 78779, 78781, 78787, 78791, 78797, 78803, 78809, 78823, 78839, 78853, 78857, 78877, 78887, 78889, 78893, 78901, 78919, 78929, 78941, 78977, 78979, 78989, 79031, 79039, 79043, 79063, 79087, 79103, 79111, 79133, 79139, 79147, 79151, 79153, 79159, 79181, 79187, 79193, 79201, 79229, 79231, 79241, 79259, 79273, 79279, 79283, 79301, 79309, 79319, 79333, 79337, 79349, 79357, 79367, 79379, 79393, 79397, 79399, 79411, 79423, 79427, 79433, 79451, 79481, 79493, 79531, 79537, 79549, 79559, 79561, 79579, 79589, 79601, 79609, 79613, 79621, 79627, 79631, 79633, 79657, 79669, 79687, 79691, 79693, 79697, 79699, 79757, 79769, 79777, 79801, 79811, 79813, 79817, 79823, 79829, 79841, 79843, 79847, 79861, 79867, 79873, 79889, 79901, 79903, 79907, 79939, 79943, 79967, 79973, 79979, 79987, 79997, 79999, 80021, 80039, 80051, 80071, 80077, 80107, 80111, 80141, 80147, 80149, 80153, 80167, 80173, 80177, 80191, 80207, 80209, 80221, 80231, 80233, 80239, 80251, 80263, 80273, 80279, 80287, 80309, 80317, 80329, 80341, 80347, 80363, 80369, 80387, 80407, 80429, 80447, 80449, 80471, 80473, 80489, 80491, 80513, 80527, 80537, 80557, 80567, 80599, 80603, 80611, 80621, 80627, 80629, 80651, 80657, 80669, 80671, 80677, 80681, 80683, 80687, 80701, 80713, 80737, 80747, 80749, 80761, 80777, 80779, 80783, 80789, 80803, 80809, 80819, 80831, 80833, 80849, 80863, 80897, 80909, 80911, 80917, 80923, 80929, 80933, 80953, 80963, 80989, 81001, 81013, 81017, 81019, 81023, 81031, 81041, 81043, 81047, 81049, 81071, 81077, 81083, 81097, 81101, 81119, 81131, 81157, 81163, 81173, 81181, 81197, 81199, 81203, 81223, 81233, 81239, 81281, 81283, 81293, 81299, 81307, 81331, 81343, 81349, 81353, 81359, 81371, 81373, 81401, 81409, 81421, 81439, 81457, 81463, 81509, 81517, 81527, 81533, 81547, 81551, 81553, 81559, 81563, 81569, 81611, 81619, 81629, 81637, 81647, 81649, 81667, 81671, 81677, 81689, 81701, 81703, 81707, 81727, 81737, 81749, 81761, 81769, 81773, 81799, 81817, 81839, 81847, 81853, 81869, 81883, 81899, 81901, 81919, 81929, 81931, 81937, 81943, 81953, 81967, 81971, 81973, 82003, 82007, 82009, 82013, 82021, 82031, 82037, 82039, 82051, 82067, 82073, 82129, 82139, 82141, 82153, 82163, 82171, 82183, 82189, 82193, 82207, 82217, 82219, 82223, 82231, 82237, 82241, 82261, 82267, 82279, 82301, 82307, 82339, 82349, 82351, 82361, 82373, 82387, 82393, 82421, 82457, 82463, 82469, 82471, 82483, 82487, 82493, 82499, 82507, 82529, 82531, 82549, 82559, 82561, 82567, 82571, 82591, 82601, 82609, 82613, 82619, 82633, 82651, 82657, 82699, 82721, 82723, 82727, 82729, 82757, 82759, 82763, 82781, 82787, 82793, 82799, 82811, 82813, 82837, 82847, 82883, 82889, 82891, 82903, 82913, 82939, 82963, 82981, 82997, 83003, 83009, 83023, 83047, 83059, 83063, 83071, 83077, 83089, 83093, 83101, 83117, 83137, 83177, 83203, 83207, 83219, 83221, 83227, 83231, 83233, 83243, 83257, 83267, 83269, 83273, 83299, 83311, 83339, 83341, 83357, 83383, 83389, 83399, 83401, 83407, 83417, 83423, 83431, 83437, 83443, 83449, 83459, 83471, 83477, 83497, 83537, 83557, 83561, 83563, 83579, 83591, 83597, 83609, 83617, 83621, 83639, 83641, 83653, 83663, 83689, 83701, 83717, 83719, 83737, 83761, 83773, 83777, 83791, 83813, 83833, 83843, 83857, 83869, 83873, 83891, 83903, 83911, 83921, 83933, 83939, 83969, 83983, 83987, 84011, 84017, 84047, 84053, 84059, 84061, 84067, 84089, 84121, 84127, 84131, 84137, 84143, 84163, 84179, 84181, 84191, 84199, 84211, 84221, 84223, 84229, 84239, 84247, 84263, 84299, 84307, 84313, 84317, 84319, 84347, 84349, 84377, 84389, 84391, 84401, 84407, 84421, 84431, 84437, 84443, 84449, 84457, 84463, 84467, 84481, 84499, 84503, 84509, 84521, 84523, 84533, 84551, 84559, 84589, 84629, 84631, 84649, 84653, 84659, 84673, 84691, 84697, 84701, 84713, 84719, 84731, 84737, 84751, 84761, 84787, 84793, 84809, 84811, 84827, 84857, 84859, 84869, 84871, 84913, 84919, 84947, 84961, 84967, 84977, 84979, 84991, 85009, 85021, 85027, 85037, 85049, 85061, 85081, 85087, 85091, 85093, 85103, 85109, 85121, 85133, 85147, 85159, 85193, 85199, 85201, 85213, 85223, 85229, 85237, 85243, 85247, 85259, 85297, 85303, 85313, 85331, 85333, 85361, 85363, 85369, 85381, 85411, 85427, 85429, 85439, 85447, 85451, 85453, 85469, 85487, 85513, 85517, 85523, 85531, 85549, 85571, 85577, 85597, 85601, 85607, 85619, 85621, 85627, 85639, 85643, 85661, 85667, 85669, 85691, 85703, 85711, 85717, 85733, 85751, 85781, 85793, 85817, 85819, 85829, 85831, 85837, 85843, 85847, 85853, 85889, 85903, 85909, 85931, 85933, 85991, 85999, 86011, 86017, 86027, 86029, 86069, 86077, 86083, 86111, 86113, 86117, 86131, 86137, 86143, 86161, 86171, 86179, 86183, 86197, 86201, 86209, 86239, 86243, 86249, 86257, 86263, 86269, 86287, 86291, 86293, 86297, 86311, 86323, 86341, 86351, 86353, 86357, 86369, 86371, 86381, 86389, 86399, 86413, 86423, 86441, 86453, 86461, 86467, 86477, 86491, 86501, 86509, 86531, 86533, 86539, 86561, 86573, 86579, 86587, 86599, 86627, 86629, 86677, 86689, 86693, 86711, 86719, 86729, 86743, 86753, 86767, 86771, 86783, 86813, 86837, 86843, 86851, 86857, 86861, 86869, 86923, 86927, 86929, 86939, 86951, 86959, 86969, 86981, 86993, 87011, 87013, 87037, 87041, 87049, 87071, 87083, 87103, 87107, 87119, 87121, 87133, 87149, 87151, 87179, 87181, 87187, 87211, 87221, 87223, 87251, 87253, 87257, 87277, 87281, 87293, 87299, 87313, 87317, 87323, 87337, 87359, 87383, 87403, 87407, 87421, 87427, 87433, 87443, 87473, 87481, 87491, 87509, 87511, 87517, 87523, 87539, 87541, 87547, 87553, 87557, 87559, 87583, 87587, 87589, 87613, 87623, 87629, 87631, 87641, 87643, 87649, 87671, 87679, 87683, 87691, 87697, 87701, 87719, 87721, 87739, 87743, 87751, 87767, 87793, 87797, 87803, 87811, 87833, 87853, 87869, 87877, 87881, 87887, 87911, 87917, 87931, 87943, 87959, 87961, 87973, 87977, 87991, 88001, 88003, 88007, 88019, 88037, 88069, 88079, 88093, 88117, 88129, 88169, 88177, 88211, 88223, 88237, 88241, 88259, 88261, 88289, 88301, 88321, 88327, 88337, 88339, 88379, 88397, 88411, 88423, 88427, 88463, 88469, 88471, 88493, 88499, 88513, 88523, 88547, 88589, 88591, 88607, 88609, 88643, 88651, 88657, 88661, 88663, 88667, 88681, 88721, 88729, 88741, 88747, 88771, 88789, 88793, 88799, 88801, 88807, 88811, 88813, 88817, 88819, 88843, 88853, 88861, 88867, 88873, 88883, 88897, 88903, 88919, 88937, 88951, 88969, 88993, 88997, 89003, 89009, 89017, 89021, 89041, 89051, 89057, 89069, 89071, 89083, 89087, 89101, 89107, 89113, 89119, 89123, 89137, 89153, 89189, 89203, 89209, 89213, 89227, 89231, 89237, 89261, 89269, 89273, 89293, 89303, 89317, 89329, 89363, 89371, 89381, 89387, 89393, 89399, 89413, 89417, 89431, 89443, 89449, 89459, 89477, 89491, 89501, 89513, 89519, 89521, 89527, 89533, 89561, 89563, 89567, 89591, 89597, 89599, 89603, 89611, 89627, 89633, 89653, 89657, 89659, 89669, 89671, 89681, 89689, 89753, 89759, 89767, 89779, 89783, 89797, 89809, 89819, 89821, 89833, 89839, 89849, 89867, 89891, 89897, 89899, 89909, 89917, 89923, 89939, 89959, 89963, 89977, 89983, 89989, 90001, 90007, 90011, 90017, 90019, 90023, 90031, 90053, 90059, 90067, 90071, 90073, 90089, 90107, 90121, 90127, 90149, 90163, 90173, 90187, 90191, 90197, 90199, 90203, 90217, 90227, 90239, 90247, 90263, 90271, 90281, 90289, 90313, 90353, 90359, 90371, 90373, 90379, 90397, 90401, 90403, 90407, 90437, 90439, 90469, 90473, 90481, 90499, 90511, 90523, 90527, 90529, 90533, 90547, 90583, 90599, 90617, 90619, 90631, 90641, 90647, 90659, 90677, 90679, 90697, 90703, 90709, 90731, 90749, 90787, 90793, 90803, 90821, 90823, 90833, 90841, 90847, 90863, 90887, 90901, 90907, 90911, 90917, 90931, 90947, 90971, 90977, 90989, 90997, 91009, 91019, 91033, 91079, 91081, 91097, 91099, 91121, 91127, 91129, 91139, 91141, 91151, 91153, 91159, 91163, 91183, 91193, 91199, 91229, 91237, 91243, 91249, 91253, 91283, 91291, 91297, 91303, 91309, 91331, 91367, 91369, 91373, 91381, 91387, 91393, 91397, 91411, 91423, 91433, 91453, 91457, 91459, 91463, 91493, 91499, 91513, 91529, 91541, 91571, 91573, 91577, 91583, 91591, 91621, 91631, 91639, 91673, 91691, 91703, 91711, 91733, 91753, 91757, 91771, 91781, 91801, 91807, 91811, 91813, 91823, 91837, 91841, 91867, 91873, 91909, 91921, 91939, 91943, 91951, 91957, 91961, 91967, 91969, 91997, 92003, 92009, 92033, 92041, 92051, 92077, 92083, 92107, 92111, 92119, 92143, 92153, 92173, 92177, 92179, 92189, 92203, 92219, 92221, 92227, 92233, 92237, 92243, 92251, 92269, 92297, 92311, 92317, 92333, 92347, 92353, 92357, 92363, 92369, 92377, 92381, 92383, 92387, 92399, 92401, 92413, 92419, 92431, 92459, 92461, 92467, 92479, 92489, 92503, 92507, 92551, 92557, 92567, 92569, 92581, 92593, 92623, 92627, 92639, 92641, 92647, 92657, 92669, 92671, 92681, 92683, 92693, 92699, 92707, 92717, 92723, 92737, 92753, 92761, 92767, 92779, 92789, 92791, 92801, 92809, 92821, 92831, 92849, 92857, 92861, 92863, 92867, 92893, 92899, 92921, 92927, 92941, 92951, 92957, 92959, 92987, 92993, 93001, 93047, 93053, 93059, 93077, 93083, 93089, 93097, 93103, 93113, 93131, 93133, 93139, 93151, 93169, 93179, 93187, 93199, 93229, 93239, 93241, 93251, 93253, 93257, 93263, 93281, 93283, 93287, 93307, 93319, 93323, 93329, 93337, 93371, 93377, 93383, 93407, 93419, 93427, 93463, 93479, 93481, 93487, 93491, 93493, 93497, 93503, 93523, 93529, 93553, 93557, 93559, 93563, 93581, 93601, 93607, 93629, 93637, 93683, 93701, 93703, 93719, 93739, 93761, 93763, 93787, 93809, 93811, 93827, 93851, 93871, 93887, 93889, 93893, 93901, 93911, 93913, 93923, 93937, 93941, 93949, 93967, 93971, 93979, 93983, 93997, 94007, 94009, 94033, 94049, 94057, 94063, 94079, 94099, 94109, 94111, 94117, 94121, 94151, 94153, 94169, 94201, 94207, 94219, 94229, 94253, 94261, 94273, 94291, 94307, 94309, 94321, 94327, 94331, 94343, 94349, 94351, 94379, 94397, 94399, 94421, 94427, 94433, 94439, 94441, 94447, 94463, 94477, 94483, 94513, 94529, 94531, 94541, 94543, 94547, 94559, 94561, 94573, 94583, 94597, 94603, 94613, 94621, 94649, 94651, 94687, 94693, 94709, 94723, 94727, 94747, 94771, 94777, 94781, 94789, 94793, 94811, 94819, 94823, 94837, 94841, 94847, 94849, 94873, 94889, 94903, 94907, 94933, 94949, 94951, 94961, 94993, 94999, 95003, 95009, 95021, 95027, 95063, 95071, 95083, 95087, 95089, 95093, 95101, 95107, 95111, 95131, 95143, 95153, 95177, 95189, 95191, 95203, 95213, 95219, 95231, 95233, 95239, 95257, 95261, 95267, 95273, 95279, 95287, 95311, 95317, 95327, 95339, 95369, 95383, 95393, 95401, 95413, 95419, 95429, 95441, 95443, 95461, 95467, 95471, 95479, 95483, 95507, 95527, 95531, 95539, 95549, 95561, 95569, 95581, 95597, 95603, 95617, 95621, 95629, 95633, 95651, 95701, 95707, 95713, 95717, 95723, 95731, 95737, 95747, 95773, 95783, 95789, 95791, 95801, 95803, 95813, 95819, 95857, 95869, 95873, 95881, 95891, 95911, 95917, 95923, 95929, 95947, 95957, 95959, 95971, 95987, 95989, 96001, 96013, 96017, 96043, 96053, 96059, 96079, 96097, 96137, 96149, 96157, 96167, 96179, 96181, 96199, 96211, 96221, 96223, 96233, 96259, 96263, 96269, 96281, 96289, 96293, 96323, 96329, 96331, 96337, 96353, 96377, 96401, 96419, 96431, 96443, 96451, 96457, 96461, 96469, 96479, 96487, 96493, 96497, 96517, 96527, 96553, 96557, 96581, 96587, 96589, 96601, 96643, 96661, 96667, 96671, 96697, 96703, 96731, 96737, 96739, 96749, 96757, 96763, 96769, 96779, 96787, 96797, 96799, 96821, 96823, 96827, 96847, 96851, 96857, 96893, 96907, 96911, 96931, 96953, 96959, 96973, 96979, 96989, 96997, 97001, 97003, 97007, 97021, 97039, 97073, 97081, 97103, 97117, 97127, 97151, 97157, 97159, 97169, 97171, 97177, 97187, 97213, 97231, 97241, 97259, 97283, 97301, 97303, 97327, 97367, 97369, 97373, 97379, 97381, 97387, 97397, 97423, 97429, 97441, 97453, 97459, 97463, 97499, 97501, 97511, 97523, 97547, 97549, 97553, 97561, 97571, 97577, 97579, 97583, 97607, 97609, 97613, 97649, 97651, 97673, 97687, 97711, 97729, 97771, 97777, 97787, 97789, 97813, 97829, 97841, 97843, 97847, 97849, 97859, 97861, 97871, 97879, 97883, 97919, 97927, 97931, 97943, 97961, 97967, 97973, 97987, 98009, 98011, 98017, 98041, 98047, 98057, 98081, 98101, 98123, 98129, 98143, 98179, 98207, 98213, 98221, 98227, 98251, 98257, 98269, 98297, 98299, 98317, 98321, 98323, 98327, 98347, 98369, 98377, 98387, 98389, 98407, 98411, 98419, 98429, 98443, 98453, 98459, 98467, 98473, 98479, 98491, 98507, 98519, 98533, 98543, 98561, 98563, 98573, 98597, 98621, 98627, 98639, 98641, 98663, 98669, 98689, 98711, 98713, 98717, 98729, 98731, 98737, 98773, 98779, 98801, 98807, 98809, 98837, 98849, 98867, 98869, 98873, 98887, 98893, 98897, 98899, 98909, 98911, 98927, 98929, 98939, 98947, 98953, 98963, 98981, 98993, 98999, 99013, 99017, 99023, 99041, 99053, 99079, 99083, 99089, 99103, 99109, 99119, 99131, 99133, 99137, 99139, 99149, 99173, 99181, 99191, 99223, 99233, 99241, 99251, 99257, 99259, 99277, 99289, 99317, 99347, 99349, 99367, 99371, 99377, 99391, 99397, 99401, 99409, 99431, 99439, 99469, 99487, 99497, 99523, 99527, 99529, 99551, 99559, 99563, 99571, 99577, 99581, 99607, 99611, 99623, 99643, 99661, 99667, 99679, 99689, 99707, 99709, 99713, 99719, 99721, 99733, 99761, 99767, 99787, 99793, 99809, 99817, 99823, 99829, 99833, 99839, 99859, 99871, 99877, 99881, 99901, 99907, 99923, 99929, 99961, 99971, 99989, 99991, 100003, 100019, 100043, 100049, 100057, 100069, 100103, 100109, 100129, 100151, 100153, 100169, 100183, 100189, 100193, 100207, 100213, 100237, 100267, 100271, 100279, 100291, 100297, 100313, 100333, 100343, 100357, 100361, 100363, 100379, 100391, 100393, 100403, 100411, 100417, 100447, 100459, 100469, 100483, 100493, 100501, 100511, 100517, 100519, 100523, 100537, 100547, 100549, 100559, 100591, 100609, 100613, 100621, 100649, 100669, 100673, 100693, 100699, 100703, 100733, 100741, 100747, 100769, 100787, 100799, 100801, 100811, 100823, 100829, 100847, 100853, 100907, 100913, 100927, 100931, 100937, 100943, 100957, 100981, 100987, 100999, 101009, 101021, 101027, 101051, 101063, 101081, 101089, 101107, 101111, 101113, 101117, 101119, 101141, 101149, 101159, 101161, 101173, 101183, 101197, 101203, 101207, 101209, 101221, 101267, 101273, 101279, 101281, 101287, 101293, 101323, 101333, 101341, 101347, 101359, 101363, 101377, 101383, 101399, 101411, 101419, 101429, 101449, 101467, 101477, 101483, 101489, 101501, 101503, 101513, 101527, 101531, 101533, 101537, 101561, 101573, 101581, 101599, 101603, 101611, 101627, 101641, 101653, 101663, 101681, 101693, 101701, 101719, 101723, 101737, 101741, 101747, 101749, 101771, 101789, 101797, 101807, 101833, 101837, 101839, 101863, 101869, 101873, 101879, 101891, 101917, 101921, 101929, 101939, 101957, 101963, 101977, 101987, 101999, 102001, 102013, 102019, 102023, 102031, 102043, 102059, 102061, 102071, 102077, 102079, 102101, 102103, 102107, 102121, 102139, 102149, 102161, 102181, 102191, 102197, 102199, 102203, 102217, 102229, 102233, 102241, 102251, 102253, 102259, 102293, 102299, 102301, 102317, 102329, 102337, 102359, 102367, 102397, 102407, 102409, 102433, 102437, 102451, 102461, 102481, 102497, 102499, 102503, 102523, 102533, 102539, 102547, 102551, 102559, 102563, 102587, 102593, 102607, 102611, 102643, 102647, 102653, 102667, 102673, 102677, 102679, 102701, 102761, 102763, 102769, 102793, 102797, 102811, 102829, 102841, 102859, 102871, 102877, 102881, 102911, 102913, 102929, 102931, 102953, 102967, 102983, 103001, 103007, 103043, 103049, 103067, 103069, 103079, 103087, 103091, 103093, 103099, 103123, 103141, 103171, 103177, 103183, 103217, 103231, 103237, 103289, 103291, 103307, 103319, 103333, 103349, 103357, 103387, 103391, 103393, 103399, 103409, 103421, 103423, 103451, 103457, 103471, 103483, 103511, 103529, 103549, 103553, 103561, 103567, 103573, 103577, 103583, 103591, 103613, 103619, 103643, 103651, 103657, 103669, 103681, 103687, 103699, 103703, 103723, 103769, 103787, 103801, 103811, 103813, 103837, 103841, 103843, 103867, 103889, 103903, 103913, 103919, 103951, 103963, 103967, 103969, 103979, 103981, 103991, 103993, 103997, 104003, 104009, 104021, 104033, 104047, 104053, 104059, 104087, 104089, 104107, 104113, 104119, 104123, 104147, 104149, 104161, 104173, 104179, 104183, 104207, 104231, 104233, 104239, 104243, 104281, 104287, 104297, 104309, 104311, 104323, 104327, 104347, 104369, 104381, 104383, 104393, 104399, 104417, 104459, 104471, 104473, 104479, 104491, 104513, 104527, 104537, 104543, 104549, 104551, 104561, 104579, 104593, 104597, 104623, 104639, 104651, 104659, 104677, 104681, 104683, 104693, 104701, 104707, 104711, 104717, 104723, 104729, }; // return 1 if p is divisable by sp, 0 otherwise static int divides(mpint *dividend, ulong divisor) { mpdigit d[2], q; int i; d[1] = 0; for(i = dividend->top-1; i >= 0; i--){ d[0] = dividend->p[i]; mpdigdiv(d, divisor, &q); d[1] = d[0] - divisor*q; } return d[1] == 0; } // return -1 if p is divisable by one of the small primes, 0 otherwise int smallprimetest(mpint *p) { int i; ulong sp; for(i = 0; i < nelem(smallprimes); i++){ sp = smallprimes[i]; if(p->top == 1 && p->p[0] <= sp) break; if(divides(p, sp)) return -1; } return 0; } drawterm-20170818/libsec/thumb.c000066400000000000000000000035431314554504700163540ustar00rootroot00000000000000#include #include #include #include #include #include enum{ ThumbTab = 1<<10 }; static void * emalloc(int n) { void *p; if(n==0) n=1; p = malloc(n); if(p == nil){ exits("out of memory"); } memset(p, 0, n); return p; } void freeThumbprints(Thumbprint *table) { Thumbprint *hd, *p, *q; for(hd = table; hd < table+ThumbTab; hd++){ for(p = hd->next; p; p = q){ q = p->next; free(p); } } free(table); } int okThumbprint(uchar *sum, Thumbprint *table) { Thumbprint *p; int i = ((sum[0]<<8) + sum[1]) & (ThumbTab-1); for(p = table[i].next; p; p = p->next) if(memcmp(sum, p->sha1, SHA1dlen) == 0) return 1; return 0; } static void loadThumbprints(char *file, Thumbprint *table, Thumbprint *crltab) { Thumbprint *entry; Biobuf *bin; char *line, *field[50]; uchar sum[SHA1dlen]; int i; bin = Bopen(file, OREAD); if(bin == nil) return; for(; (line = Brdstr(bin, '\n', 1)) != 0; free(line)){ if(tokenize(line, field, nelem(field)) < 2) continue; if(strcmp(field[0], "#include") == 0){ loadThumbprints(field[1], table, crltab); continue; } if(strcmp(field[0], "x509") != 0 || strncmp(field[1], "sha1=", strlen("sha1=")) != 0) continue; field[1] += strlen("sha1="); dec16(sum, sizeof(sum), field[1], strlen(field[1])); if(crltab && okThumbprint(sum, crltab)) continue; entry = (Thumbprint*)emalloc(sizeof(*entry)); memcpy(entry->sha1, sum, SHA1dlen); i = ((sum[0]<<8) + sum[1]) & (ThumbTab-1); entry->next = table[i].next; table[i].next = entry; } Bterm(bin); } Thumbprint * initThumbprints(char *ok, char *crl) { Thumbprint *table, *crltab = nil; if(crl){ crltab = emalloc(ThumbTab * sizeof(*table)); loadThumbprints(crl, crltab, nil); } table = emalloc(ThumbTab * sizeof(*table)); loadThumbprints(ok, table, crltab); free(crltab); return table; } drawterm-20170818/libsec/tlshand.c000066400000000000000000001512441314554504700166740ustar00rootroot00000000000000#include #include #include #include #include #include // The main groups of functions are: // client/server - main handshake protocol definition // message functions - formating handshake messages // cipher choices - catalog of digest and encrypt algorithms // security functions - PKCS#1, sslHMAC, session keygen // general utility functions - malloc, serialization // The handshake protocol builds on the TLS/SSL3 record layer protocol, // which is implemented in kernel device #a. See also /lib/rfc/rfc2246. enum { TLSFinishedLen = 12, SSL3FinishedLen = MD5dlen+SHA1dlen, MaxKeyData = 104, // amount of secret we may need MaxChunk = 1<<14, RandomSize = 32, SidSize = 32, MasterSecretSize = 48, AQueue = 0, AFlush = 1, }; typedef struct TlsSec TlsSec; typedef struct Bytes{ int len; uchar data[1]; // [len] } Bytes; typedef struct Ints{ int len; int data[1]; // [len] } Ints; typedef struct Algs{ char *enc; char *digest; int nsecret; int tlsid; int ok; } Algs; typedef struct Finished{ uchar verify[SSL3FinishedLen]; int n; } Finished; typedef struct TlsConnection{ TlsSec *sec; // security management goo int hand, ctl; // record layer file descriptors int erred; // set when tlsError called int (*trace)(char*fmt, ...); // for debugging int version; // protocol we are speaking int verset; // version has been set int ver2hi; // server got a version 2 hello int isClient; // is this the client or server? Bytes *sid; // SessionID Bytes *cert; // only last - no chain Lock statelk; int state; // must be set using setstate // input buffer for handshake messages uchar buf[MaxChunk+2048]; uchar *rp, *ep; uchar crandom[RandomSize]; // client random uchar srandom[RandomSize]; // server random int clientVersion; // version in ClientHello char *digest; // name of digest algorithm to use char *enc; // name of encryption algorithm to use int nsecret; // amount of secret data to init keys // for finished messages MD5state hsmd5; // handshake hash SHAstate hssha1; // handshake hash Finished finished; } TlsConnection; typedef struct Msg{ int tag; union { struct { int version; uchar random[RandomSize]; Bytes* sid; Ints* ciphers; Bytes* compressors; } clientHello; struct { int version; uchar random[RandomSize]; Bytes* sid; int cipher; int compressor; } serverHello; struct { int ncert; Bytes **certs; } certificate; struct { Bytes *types; int nca; Bytes **cas; } certificateRequest; struct { Bytes *key; } clientKeyExchange; Finished finished; } u; } Msg; typedef struct TlsSec{ char *server; // name of remote; nil for server int ok; // <0 killed; ==0 in progress; >0 reusable RSApub *rsapub; AuthRpc *rpc; // factotum for rsa private key uchar sec[MasterSecretSize]; // master secret uchar crandom[RandomSize]; // client random uchar srandom[RandomSize]; // server random int clientVers; // version in ClientHello int vers; // final version // byte generation and handshake checksum void (*prf)(uchar*, int, uchar*, int, char*, uchar*, int, uchar*, int); void (*setFinished)(TlsSec*, MD5state, SHAstate, uchar*, int); int nfin; } TlsSec; enum { TLSVersion = 0x0301, SSL3Version = 0x0300, ProtocolVersion = 0x0301, // maximum version we speak MinProtoVersion = 0x0300, // limits on version we accept MaxProtoVersion = 0x03ff, }; // handshake type enum { HHelloRequest, HClientHello, HServerHello, HSSL2ClientHello = 9, /* local convention; see devtls.c */ HCertificate = 11, HServerKeyExchange, HCertificateRequest, HServerHelloDone, HCertificateVerify, HClientKeyExchange, HFinished = 20, HMax }; // alerts enum { ECloseNotify = 0, EUnexpectedMessage = 10, EBadRecordMac = 20, EDecryptionFailed = 21, ERecordOverflow = 22, EDecompressionFailure = 30, EHandshakeFailure = 40, ENoCertificate = 41, EBadCertificate = 42, EUnsupportedCertificate = 43, ECertificateRevoked = 44, ECertificateExpired = 45, ECertificateUnknown = 46, EIllegalParameter = 47, EUnknownCa = 48, EAccessDenied = 49, EDecodeError = 50, EDecryptError = 51, EExportRestriction = 60, EProtocolVersion = 70, EInsufficientSecurity = 71, EInternalError = 80, EUserCanceled = 90, ENoRenegotiation = 100, EMax = 256 }; // cipher suites enum { TLS_NULL_WITH_NULL_NULL = 0x0000, TLS_RSA_WITH_NULL_MD5 = 0x0001, TLS_RSA_WITH_NULL_SHA = 0x0002, TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003, TLS_RSA_WITH_RC4_128_MD5 = 0x0004, TLS_RSA_WITH_RC4_128_SHA = 0x0005, TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0X0006, TLS_RSA_WITH_IDEA_CBC_SHA = 0X0007, TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0X0008, TLS_RSA_WITH_DES_CBC_SHA = 0X0009, TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0X000A, TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0X000B, TLS_DH_DSS_WITH_DES_CBC_SHA = 0X000C, TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0X000D, TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0X000E, TLS_DH_RSA_WITH_DES_CBC_SHA = 0X000F, TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0X0010, TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0X0011, TLS_DHE_DSS_WITH_DES_CBC_SHA = 0X0012, TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0X0013, // ZZZ must be implemented for tls1.0 compliance TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0X0014, TLS_DHE_RSA_WITH_DES_CBC_SHA = 0X0015, TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0X0016, TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017, TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018, TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0X0019, TLS_DH_anon_WITH_DES_CBC_SHA = 0X001A, TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0X001B, TLS_RSA_WITH_AES_128_CBC_SHA = 0X002f, // aes, aka rijndael with 128 bit blocks TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0X0030, TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0X0031, TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0X0032, TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0X0033, TLS_DH_anon_WITH_AES_128_CBC_SHA = 0X0034, TLS_RSA_WITH_AES_256_CBC_SHA = 0X0035, TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0X0036, TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0X0037, TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0X0038, TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0X0039, TLS_DH_anon_WITH_AES_256_CBC_SHA = 0X003A, CipherMax }; // compression methods enum { CompressionNull = 0, CompressionMax }; static Algs cipherAlgs[] = { {"rc4_128", "md5", 2 * (16 + MD5dlen), TLS_RSA_WITH_RC4_128_MD5}, {"rc4_128", "sha1", 2 * (16 + SHA1dlen), TLS_RSA_WITH_RC4_128_SHA}, {"3des_ede_cbc","sha1",2*(4*8+SHA1dlen), TLS_RSA_WITH_3DES_EDE_CBC_SHA}, }; static uchar compressors[] = { CompressionNull, }; static TlsConnection *tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...)); static TlsConnection *tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...)); static void msgClear(Msg *m); static char* msgPrint(char *buf, int n, Msg *m); static int msgRecv(TlsConnection *c, Msg *m); static int msgSend(TlsConnection *c, Msg *m, int act); static void tlsError(TlsConnection *c, int err, char *msg, ...); #pragma varargck argpos tlsError 3 static int setVersion(TlsConnection *c, int version); static int finishedMatch(TlsConnection *c, Finished *f); static void tlsConnectionFree(TlsConnection *c); static int setAlgs(TlsConnection *c, int a); static int okCipher(Ints *cv); static int okCompression(Bytes *cv); static int initCiphers(void); static Ints* makeciphers(void); static TlsSec* tlsSecInits(int cvers, uchar *csid, int ncsid, uchar *crandom, uchar *ssid, int *nssid, uchar *srandom); static int tlsSecSecrets(TlsSec *sec, int vers, uchar *epm, int nepm, uchar *kd, int nkd); static TlsSec* tlsSecInitc(int cvers, uchar *crandom); static int tlsSecSecretc(TlsSec *sec, uchar *sid, int nsid, uchar *srandom, uchar *cert, int ncert, int vers, uchar **epm, int *nepm, uchar *kd, int nkd); static int tlsSecFinished(TlsSec *sec, MD5state md5, SHAstate sha1, uchar *fin, int nfin, int isclient); static void tlsSecOk(TlsSec *sec); static void tlsSecKill(TlsSec *sec); static void tlsSecClose(TlsSec *sec); static void setMasterSecret(TlsSec *sec, Bytes *pm); static void serverMasterSecret(TlsSec *sec, uchar *epm, int nepm); static void setSecrets(TlsSec *sec, uchar *kd, int nkd); static int clientMasterSecret(TlsSec *sec, RSApub *pub, uchar **epm, int *nepm); static Bytes *pkcs1_encrypt(Bytes* data, RSApub* key, int blocktype); static Bytes *pkcs1_decrypt(TlsSec *sec, uchar *epm, int nepm); static void tlsSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient); static void sslSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient); static void sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1); static int setVers(TlsSec *sec, int version); static AuthRpc* factotum_rsa_open(uchar *cert, int certlen); static mpint* factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher); static void factotum_rsa_close(AuthRpc*rpc); static void* emalloc(int); static void* erealloc(void*, int); static void put32(uchar *p, u32int); static void put24(uchar *p, int); static void put16(uchar *p, int); static u32int get32(uchar *p); static int get24(uchar *p); static int get16(uchar *p); static Bytes* newbytes(int len); static Bytes* makebytes(uchar* buf, int len); static void freebytes(Bytes* b); static Ints* newints(int len); static Ints* makeints(int* buf, int len); static void freeints(Ints* b); //================= client/server ======================== // push TLS onto fd, returning new (application) file descriptor // or -1 if error. int tlsServer(int fd, TLSconn *conn) { char buf[8]; char dname[64]; int n, data, ctl, hand; TlsConnection *tls; if(conn == nil) return -1; ctl = open("#a/tls/clone", ORDWR); if(ctl < 0) return -1; n = read(ctl, buf, sizeof(buf)-1); if(n < 0){ close(ctl); return -1; } buf[n] = 0; sprint(conn->dir, "#a/tls/%s", buf); sprint(dname, "#a/tls/%s/hand", buf); hand = open(dname, ORDWR); if(hand < 0){ close(ctl); return -1; } fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion); tls = tlsServer2(ctl, hand, conn->cert, conn->certlen, conn->trace); sprint(dname, "#a/tls/%s/data", buf); data = open(dname, ORDWR); close(fd); close(hand); close(ctl); if(data < 0){ return -1; } if(tls == nil){ close(data); return -1; } if(conn->cert) free(conn->cert); conn->cert = 0; // client certificates are not yet implemented conn->certlen = 0; conn->sessionIDlen = tls->sid->len; conn->sessionID = emalloc(conn->sessionIDlen); memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen); tlsConnectionFree(tls); return data; } // push TLS onto fd, returning new (application) file descriptor // or -1 if error. int tlsClient(int fd, TLSconn *conn) { char buf[8]; char dname[64]; int n, data, ctl, hand; TlsConnection *tls; if(!conn) return -1; ctl = open("#a/tls/clone", ORDWR); if(ctl < 0) return -1; n = read(ctl, buf, sizeof(buf)-1); if(n < 0){ close(ctl); return -1; } buf[n] = 0; sprint(conn->dir, "#a/tls/%s", buf); sprint(dname, "#a/tls/%s/hand", buf); hand = open(dname, ORDWR); if(hand < 0){ close(ctl); return -1; } sprint(dname, "#a/tls/%s/data", buf); data = open(dname, ORDWR); if(data < 0) return -1; fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion); tls = tlsClient2(ctl, hand, conn->sessionID, conn->sessionIDlen, conn->trace); close(fd); close(hand); close(ctl); if(tls == nil){ close(data); return -1; } conn->certlen = tls->cert->len; conn->cert = emalloc(conn->certlen); memcpy(conn->cert, tls->cert->data, conn->certlen); conn->sessionIDlen = tls->sid->len; conn->sessionID = emalloc(conn->sessionIDlen); memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen); tlsConnectionFree(tls); return data; } static TlsConnection * tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...)) { TlsConnection *c; Msg m; Bytes *csid; uchar sid[SidSize], kd[MaxKeyData]; char *secrets; int cipher, compressor, nsid, rv; if(trace) trace("tlsServer2\n"); if(!initCiphers()) return nil; c = emalloc(sizeof(TlsConnection)); c->ctl = ctl; c->hand = hand; c->trace = trace; c->version = ProtocolVersion; memset(&m, 0, sizeof(m)); if(!msgRecv(c, &m)){ if(trace) trace("initial msgRecv failed\n"); goto Err; } if(m.tag != HClientHello) { tlsError(c, EUnexpectedMessage, "expected a client hello"); goto Err; } c->clientVersion = m.u.clientHello.version; if(trace) trace("ClientHello version %x\n", c->clientVersion); if(setVersion(c, m.u.clientHello.version) < 0) { tlsError(c, EIllegalParameter, "incompatible version"); goto Err; } memmove(c->crandom, m.u.clientHello.random, RandomSize); cipher = okCipher(m.u.clientHello.ciphers); if(cipher < 0) { // reply with EInsufficientSecurity if we know that's the case if(cipher == -2) tlsError(c, EInsufficientSecurity, "cipher suites too weak"); else tlsError(c, EHandshakeFailure, "no matching cipher suite"); goto Err; } if(!setAlgs(c, cipher)){ tlsError(c, EHandshakeFailure, "no matching cipher suite"); goto Err; } compressor = okCompression(m.u.clientHello.compressors); if(compressor < 0) { tlsError(c, EHandshakeFailure, "no matching compressor"); goto Err; } csid = m.u.clientHello.sid; if(trace) trace(" cipher %d, compressor %d, csidlen %d\n", cipher, compressor, csid->len); c->sec = tlsSecInits(c->clientVersion, csid->data, csid->len, c->crandom, sid, &nsid, c->srandom); if(c->sec == nil){ tlsError(c, EHandshakeFailure, "can't initialize security: %r"); goto Err; } c->sec->rpc = factotum_rsa_open(cert, ncert); if(c->sec->rpc == nil){ tlsError(c, EHandshakeFailure, "factotum_rsa_open: %r"); goto Err; } c->sec->rsapub = X509toRSApub(cert, ncert, nil, 0); msgClear(&m); m.tag = HServerHello; m.u.serverHello.version = c->version; memmove(m.u.serverHello.random, c->srandom, RandomSize); m.u.serverHello.cipher = cipher; m.u.serverHello.compressor = compressor; c->sid = makebytes(sid, nsid); m.u.serverHello.sid = makebytes(c->sid->data, c->sid->len); if(!msgSend(c, &m, AQueue)) goto Err; msgClear(&m); m.tag = HCertificate; m.u.certificate.ncert = 1; m.u.certificate.certs = emalloc(m.u.certificate.ncert * sizeof(Bytes)); m.u.certificate.certs[0] = makebytes(cert, ncert); if(!msgSend(c, &m, AQueue)) goto Err; msgClear(&m); m.tag = HServerHelloDone; if(!msgSend(c, &m, AFlush)) goto Err; msgClear(&m); if(!msgRecv(c, &m)) goto Err; if(m.tag != HClientKeyExchange) { tlsError(c, EUnexpectedMessage, "expected a client key exchange"); goto Err; } if(tlsSecSecrets(c->sec, c->version, m.u.clientKeyExchange.key->data, m.u.clientKeyExchange.key->len, kd, c->nsecret) < 0){ tlsError(c, EHandshakeFailure, "couldn't set secrets: %r"); goto Err; } if(trace) trace("tls secrets\n"); secrets = (char*)emalloc(2*c->nsecret); enc64(secrets, 2*c->nsecret, kd, c->nsecret); rv = fprint(c->ctl, "secret %s %s 0 %s", c->digest, c->enc, secrets); memset(secrets, 0, 2*c->nsecret); free(secrets); memset(kd, 0, c->nsecret); if(rv < 0){ tlsError(c, EHandshakeFailure, "can't set keys: %r"); goto Err; } msgClear(&m); /* no CertificateVerify; skip to Finished */ if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 1) < 0){ tlsError(c, EInternalError, "can't set finished: %r"); goto Err; } if(!msgRecv(c, &m)) goto Err; if(m.tag != HFinished) { tlsError(c, EUnexpectedMessage, "expected a finished"); goto Err; } if(!finishedMatch(c, &m.u.finished)) { tlsError(c, EHandshakeFailure, "finished verification failed"); goto Err; } msgClear(&m); /* change cipher spec */ if(fprint(c->ctl, "changecipher") < 0){ tlsError(c, EInternalError, "can't enable cipher: %r"); goto Err; } if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 0) < 0){ tlsError(c, EInternalError, "can't set finished: %r"); goto Err; } m.tag = HFinished; m.u.finished = c->finished; if(!msgSend(c, &m, AFlush)) goto Err; msgClear(&m); if(trace) trace("tls finished\n"); if(fprint(c->ctl, "opened") < 0) goto Err; tlsSecOk(c->sec); return c; Err: msgClear(&m); tlsConnectionFree(c); return 0; } static TlsConnection * tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...)) { TlsConnection *c; Msg m; uchar kd[MaxKeyData], *epm; char *secrets; int creq, nepm, rv; if(!initCiphers()) return nil; epm = nil; c = emalloc(sizeof(TlsConnection)); c->version = ProtocolVersion; c->ctl = ctl; c->hand = hand; c->trace = trace; c->isClient = 1; c->clientVersion = c->version; c->sec = tlsSecInitc(c->clientVersion, c->crandom); if(c->sec == nil) goto Err; /* client hello */ memset(&m, 0, sizeof(m)); m.tag = HClientHello; m.u.clientHello.version = c->clientVersion; memmove(m.u.clientHello.random, c->crandom, RandomSize); m.u.clientHello.sid = makebytes(csid, ncsid); m.u.clientHello.ciphers = makeciphers(); m.u.clientHello.compressors = makebytes(compressors,sizeof(compressors)); if(!msgSend(c, &m, AFlush)) goto Err; msgClear(&m); /* server hello */ if(!msgRecv(c, &m)) goto Err; if(m.tag != HServerHello) { tlsError(c, EUnexpectedMessage, "expected a server hello"); goto Err; } if(setVersion(c, m.u.serverHello.version) < 0) { tlsError(c, EIllegalParameter, "incompatible version %r"); goto Err; } memmove(c->srandom, m.u.serverHello.random, RandomSize); c->sid = makebytes(m.u.serverHello.sid->data, m.u.serverHello.sid->len); if(c->sid->len != 0 && c->sid->len != SidSize) { tlsError(c, EIllegalParameter, "invalid server session identifier"); goto Err; } if(!setAlgs(c, m.u.serverHello.cipher)) { tlsError(c, EIllegalParameter, "invalid cipher suite"); goto Err; } if(m.u.serverHello.compressor != CompressionNull) { tlsError(c, EIllegalParameter, "invalid compression"); goto Err; } msgClear(&m); /* certificate */ if(!msgRecv(c, &m) || m.tag != HCertificate) { tlsError(c, EUnexpectedMessage, "expected a certificate"); goto Err; } if(m.u.certificate.ncert < 1) { tlsError(c, EIllegalParameter, "runt certificate"); goto Err; } c->cert = makebytes(m.u.certificate.certs[0]->data, m.u.certificate.certs[0]->len); msgClear(&m); /* server key exchange (optional) */ if(!msgRecv(c, &m)) goto Err; if(m.tag == HServerKeyExchange) { tlsError(c, EUnexpectedMessage, "got an server key exchange"); goto Err; // If implementing this later, watch out for rollback attack // described in Wagner Schneier 1996, section 4.4. } /* certificate request (optional) */ creq = 0; if(m.tag == HCertificateRequest) { creq = 1; msgClear(&m); if(!msgRecv(c, &m)) goto Err; } if(m.tag != HServerHelloDone) { tlsError(c, EUnexpectedMessage, "expected a server hello done"); goto Err; } msgClear(&m); if(tlsSecSecretc(c->sec, c->sid->data, c->sid->len, c->srandom, c->cert->data, c->cert->len, c->version, &epm, &nepm, kd, c->nsecret) < 0){ tlsError(c, EBadCertificate, "invalid x509/rsa certificate"); goto Err; } secrets = (char*)emalloc(2*c->nsecret); enc64(secrets, 2*c->nsecret, kd, c->nsecret); rv = fprint(c->ctl, "secret %s %s 1 %s", c->digest, c->enc, secrets); memset(secrets, 0, 2*c->nsecret); free(secrets); memset(kd, 0, c->nsecret); if(rv < 0){ tlsError(c, EHandshakeFailure, "can't set keys: %r"); goto Err; } if(creq) { /* send a zero length certificate */ m.tag = HCertificate; if(!msgSend(c, &m, AFlush)) goto Err; msgClear(&m); } /* client key exchange */ m.tag = HClientKeyExchange; m.u.clientKeyExchange.key = makebytes(epm, nepm); free(epm); epm = nil; if(m.u.clientKeyExchange.key == nil) { tlsError(c, EHandshakeFailure, "can't set secret: %r"); goto Err; } if(!msgSend(c, &m, AFlush)) goto Err; msgClear(&m); /* change cipher spec */ if(fprint(c->ctl, "changecipher") < 0){ tlsError(c, EInternalError, "can't enable cipher: %r"); goto Err; } // Cipherchange must occur immediately before Finished to avoid // potential hole; see section 4.3 of Wagner Schneier 1996. if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 1) < 0){ tlsError(c, EInternalError, "can't set finished 1: %r"); goto Err; } m.tag = HFinished; m.u.finished = c->finished; if(!msgSend(c, &m, AFlush)) { fprint(2, "tlsClient nepm=%d\n", nepm); tlsError(c, EInternalError, "can't flush after client Finished: %r"); goto Err; } msgClear(&m); if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 0) < 0){ fprint(2, "tlsClient nepm=%d\n", nepm); tlsError(c, EInternalError, "can't set finished 0: %r"); goto Err; } if(!msgRecv(c, &m)) { fprint(2, "tlsClient nepm=%d\n", nepm); tlsError(c, EInternalError, "can't read server Finished: %r"); goto Err; } if(m.tag != HFinished) { fprint(2, "tlsClient nepm=%d\n", nepm); tlsError(c, EUnexpectedMessage, "expected a Finished msg from server"); goto Err; } if(!finishedMatch(c, &m.u.finished)) { tlsError(c, EHandshakeFailure, "finished verification failed"); goto Err; } msgClear(&m); if(fprint(c->ctl, "opened") < 0){ if(trace) trace("unable to do final open: %r\n"); goto Err; } tlsSecOk(c->sec); return c; Err: free(epm); msgClear(&m); tlsConnectionFree(c); return 0; } //================= message functions ======================== static uchar sendbuf[9000], *sendp; static int msgSend(TlsConnection *c, Msg *m, int act) { uchar *p; // sendp = start of new message; p = write pointer int nn, n, i; if(sendp == nil) sendp = sendbuf; p = sendp; if(c->trace) c->trace("send %s", msgPrint((char*)p, (sizeof sendbuf) - (p-sendbuf), m)); p[0] = m->tag; // header - fill in size later p += 4; switch(m->tag) { default: tlsError(c, EInternalError, "can't encode a %d", m->tag); goto Err; case HClientHello: // version put16(p, m->u.clientHello.version); p += 2; // random memmove(p, m->u.clientHello.random, RandomSize); p += RandomSize; // sid n = m->u.clientHello.sid->len; assert(n < 256); p[0] = n; memmove(p+1, m->u.clientHello.sid->data, n); p += n+1; n = m->u.clientHello.ciphers->len; assert(n > 0 && n < 200); put16(p, n*2); p += 2; for(i=0; iu.clientHello.ciphers->data[i]); p += 2; } n = m->u.clientHello.compressors->len; assert(n > 0); p[0] = n; memmove(p+1, m->u.clientHello.compressors->data, n); p += n+1; break; case HServerHello: put16(p, m->u.serverHello.version); p += 2; // random memmove(p, m->u.serverHello.random, RandomSize); p += RandomSize; // sid n = m->u.serverHello.sid->len; assert(n < 256); p[0] = n; memmove(p+1, m->u.serverHello.sid->data, n); p += n+1; put16(p, m->u.serverHello.cipher); p += 2; p[0] = m->u.serverHello.compressor; p += 1; break; case HServerHelloDone: break; case HCertificate: nn = 0; for(i = 0; i < m->u.certificate.ncert; i++) nn += 3 + m->u.certificate.certs[i]->len; if(p + 3 + nn - sendbuf > sizeof(sendbuf)) { tlsError(c, EInternalError, "output buffer too small for certificate"); goto Err; } put24(p, nn); p += 3; for(i = 0; i < m->u.certificate.ncert; i++){ put24(p, m->u.certificate.certs[i]->len); p += 3; memmove(p, m->u.certificate.certs[i]->data, m->u.certificate.certs[i]->len); p += m->u.certificate.certs[i]->len; } break; case HClientKeyExchange: n = m->u.clientKeyExchange.key->len; if(c->version != SSL3Version){ put16(p, n); p += 2; } memmove(p, m->u.clientKeyExchange.key->data, n); p += n; break; case HFinished: memmove(p, m->u.finished.verify, m->u.finished.n); p += m->u.finished.n; break; } // go back and fill in size n = p-sendp; assert(p <= sendbuf+sizeof(sendbuf)); put24(sendp+1, n-4); // remember hash of Handshake messages if(m->tag != HHelloRequest) { md5(sendp, n, 0, &c->hsmd5); sha1(sendp, n, 0, &c->hssha1); } sendp = p; if(act == AFlush){ sendp = sendbuf; if(write(c->hand, sendbuf, p-sendbuf) < 0){ fprint(2, "write error: %r\n"); goto Err; } } msgClear(m); return 1; Err: msgClear(m); return 0; } static uchar* tlsReadN(TlsConnection *c, int n) { uchar *p; int nn, nr; nn = c->ep - c->rp; if(nn < n){ if(c->rp != c->buf){ memmove(c->buf, c->rp, nn); c->rp = c->buf; c->ep = &c->buf[nn]; } for(; nn < n; nn += nr) { nr = read(c->hand, &c->rp[nn], n - nn); if(nr <= 0) return nil; c->ep += nr; } } p = c->rp; c->rp += n; return p; } static int msgRecv(TlsConnection *c, Msg *m) { uchar *p; int type, n, nn, i, nsid, nrandom, nciph; for(;;) { p = tlsReadN(c, 4); if(p == nil) return 0; type = p[0]; n = get24(p+1); if(type != HHelloRequest) break; if(n != 0) { tlsError(c, EDecodeError, "invalid hello request during handshake"); return 0; } } if(n > sizeof(c->buf)) { tlsError(c, EDecodeError, "handshake message too long %d %d", n, sizeof(c->buf)); return 0; } if(type == HSSL2ClientHello){ /* Cope with an SSL3 ClientHello expressed in SSL2 record format. This is sent by some clients that we must interoperate with, such as Java's JSSE and Microsoft's Internet Explorer. */ p = tlsReadN(c, n); if(p == nil) return 0; md5(p, n, 0, &c->hsmd5); sha1(p, n, 0, &c->hssha1); m->tag = HClientHello; if(n < 22) goto Short; m->u.clientHello.version = get16(p+1); p += 3; n -= 3; nn = get16(p); /* cipher_spec_len */ nsid = get16(p + 2); nrandom = get16(p + 4); p += 6; n -= 6; if(nsid != 0 /* no sid's, since shouldn't restart using ssl2 header */ || nrandom < 16 || nn % 3) goto Err; if(c->trace && (n - nrandom != nn)) c->trace("n-nrandom!=nn: n=%d nrandom=%d nn=%d\n", n, nrandom, nn); /* ignore ssl2 ciphers and look for {0x00, ssl3 cipher} */ nciph = 0; for(i = 0; i < nn; i += 3) if(p[i] == 0) nciph++; m->u.clientHello.ciphers = newints(nciph); nciph = 0; for(i = 0; i < nn; i += 3) if(p[i] == 0) m->u.clientHello.ciphers->data[nciph++] = get16(&p[i + 1]); p += nn; m->u.clientHello.sid = makebytes(nil, 0); if(nrandom > RandomSize) nrandom = RandomSize; memset(m->u.clientHello.random, 0, RandomSize - nrandom); memmove(&m->u.clientHello.random[RandomSize - nrandom], p, nrandom); m->u.clientHello.compressors = newbytes(1); m->u.clientHello.compressors->data[0] = CompressionNull; goto Ok; } md5(p, 4, 0, &c->hsmd5); sha1(p, 4, 0, &c->hssha1); p = tlsReadN(c, n); if(p == nil) return 0; md5(p, n, 0, &c->hsmd5); sha1(p, n, 0, &c->hssha1); m->tag = type; switch(type) { default: tlsError(c, EUnexpectedMessage, "can't decode a %d", type); goto Err; case HClientHello: if(n < 2) goto Short; m->u.clientHello.version = get16(p); p += 2; n -= 2; if(n < RandomSize) goto Short; memmove(m->u.clientHello.random, p, RandomSize); p += RandomSize; n -= RandomSize; if(n < 1 || n < p[0]+1) goto Short; m->u.clientHello.sid = makebytes(p+1, p[0]); p += m->u.clientHello.sid->len+1; n -= m->u.clientHello.sid->len+1; if(n < 2) goto Short; nn = get16(p); p += 2; n -= 2; if((nn & 1) || n < nn || nn < 2) goto Short; m->u.clientHello.ciphers = newints(nn >> 1); for(i = 0; i < nn; i += 2) m->u.clientHello.ciphers->data[i >> 1] = get16(&p[i]); p += nn; n -= nn; if(n < 1 || n < p[0]+1 || p[0] == 0) goto Short; nn = p[0]; m->u.clientHello.compressors = newbytes(nn); memmove(m->u.clientHello.compressors->data, p+1, nn); n -= nn + 1; break; case HServerHello: if(n < 2) goto Short; m->u.serverHello.version = get16(p); p += 2; n -= 2; if(n < RandomSize) goto Short; memmove(m->u.serverHello.random, p, RandomSize); p += RandomSize; n -= RandomSize; if(n < 1 || n < p[0]+1) goto Short; m->u.serverHello.sid = makebytes(p+1, p[0]); p += m->u.serverHello.sid->len+1; n -= m->u.serverHello.sid->len+1; if(n < 3) goto Short; m->u.serverHello.cipher = get16(p); m->u.serverHello.compressor = p[2]; n -= 3; break; case HCertificate: if(n < 3) goto Short; nn = get24(p); p += 3; n -= 3; if(n != nn) goto Short; /* certs */ i = 0; while(n > 0) { if(n < 3) goto Short; nn = get24(p); p += 3; n -= 3; if(nn > n) goto Short; m->u.certificate.ncert = i+1; m->u.certificate.certs = erealloc(m->u.certificate.certs, (i+1)*sizeof(Bytes)); m->u.certificate.certs[i] = makebytes(p, nn); p += nn; n -= nn; i++; } break; case HCertificateRequest: if(n < 2) goto Short; nn = get16(p); p += 2; n -= 2; if(nn < 1 || nn > n) goto Short; m->u.certificateRequest.types = makebytes(p, nn); nn = get24(p); p += 3; n -= 3; if(nn == 0 || n != nn) goto Short; /* cas */ i = 0; while(n > 0) { if(n < 2) goto Short; nn = get16(p); p += 2; n -= 2; if(nn < 1 || nn > n) goto Short; m->u.certificateRequest.nca = i+1; m->u.certificateRequest.cas = erealloc(m->u.certificateRequest.cas, (i+1)*sizeof(Bytes)); m->u.certificateRequest.cas[i] = makebytes(p, nn); p += nn; n -= nn; i++; } break; case HServerHelloDone: break; case HClientKeyExchange: /* * this message depends upon the encryption selected * assume rsa. */ if(c->version == SSL3Version) nn = n; else{ if(n < 2) goto Short; nn = get16(p); p += 2; n -= 2; } if(n < nn) goto Short; m->u.clientKeyExchange.key = makebytes(p, nn); n -= nn; break; case HFinished: m->u.finished.n = c->finished.n; if(n < m->u.finished.n) goto Short; memmove(m->u.finished.verify, p, m->u.finished.n); n -= m->u.finished.n; break; } if(type != HClientHello && n != 0) goto Short; Ok: if(c->trace){ char buf[8000]; c->trace("recv %s", msgPrint(buf, sizeof buf, m)); } return 1; Short: tlsError(c, EDecodeError, "handshake message has invalid length"); Err: msgClear(m); return 0; } static void msgClear(Msg *m) { int i; switch(m->tag) { default: sysfatal("msgClear: unknown message type: %d", m->tag); case HHelloRequest: break; case HClientHello: freebytes(m->u.clientHello.sid); freeints(m->u.clientHello.ciphers); freebytes(m->u.clientHello.compressors); break; case HServerHello: freebytes(m->u.clientHello.sid); break; case HCertificate: for(i=0; iu.certificate.ncert; i++) freebytes(m->u.certificate.certs[i]); free(m->u.certificate.certs); break; case HCertificateRequest: freebytes(m->u.certificateRequest.types); for(i=0; iu.certificateRequest.nca; i++) freebytes(m->u.certificateRequest.cas[i]); free(m->u.certificateRequest.cas); break; case HServerHelloDone: break; case HClientKeyExchange: freebytes(m->u.clientKeyExchange.key); break; case HFinished: break; } memset(m, 0, sizeof(Msg)); } static char * bytesPrint(char *bs, char *be, char *s0, Bytes *b, char *s1) { int i; if(s0) bs = seprint(bs, be, "%s", s0); bs = seprint(bs, be, "["); if(b == nil) bs = seprint(bs, be, "nil"); else for(i=0; ilen; i++) bs = seprint(bs, be, "%.2x ", b->data[i]); bs = seprint(bs, be, "]"); if(s1) bs = seprint(bs, be, "%s", s1); return bs; } static char * intsPrint(char *bs, char *be, char *s0, Ints *b, char *s1) { int i; if(s0) bs = seprint(bs, be, "%s", s0); bs = seprint(bs, be, "["); if(b == nil) bs = seprint(bs, be, "nil"); else for(i=0; ilen; i++) bs = seprint(bs, be, "%x ", b->data[i]); bs = seprint(bs, be, "]"); if(s1) bs = seprint(bs, be, "%s", s1); return bs; } static char* msgPrint(char *buf, int n, Msg *m) { int i; char *bs = buf, *be = buf+n; switch(m->tag) { default: bs = seprint(bs, be, "unknown %d\n", m->tag); break; case HClientHello: bs = seprint(bs, be, "ClientHello\n"); bs = seprint(bs, be, "\tversion: %.4x\n", m->u.clientHello.version); bs = seprint(bs, be, "\trandom: "); for(i=0; iu.clientHello.random[i]); bs = seprint(bs, be, "\n"); bs = bytesPrint(bs, be, "\tsid: ", m->u.clientHello.sid, "\n"); bs = intsPrint(bs, be, "\tciphers: ", m->u.clientHello.ciphers, "\n"); bs = bytesPrint(bs, be, "\tcompressors: ", m->u.clientHello.compressors, "\n"); break; case HServerHello: bs = seprint(bs, be, "ServerHello\n"); bs = seprint(bs, be, "\tversion: %.4x\n", m->u.serverHello.version); bs = seprint(bs, be, "\trandom: "); for(i=0; iu.serverHello.random[i]); bs = seprint(bs, be, "\n"); bs = bytesPrint(bs, be, "\tsid: ", m->u.serverHello.sid, "\n"); bs = seprint(bs, be, "\tcipher: %.4x\n", m->u.serverHello.cipher); bs = seprint(bs, be, "\tcompressor: %.2x\n", m->u.serverHello.compressor); break; case HCertificate: bs = seprint(bs, be, "Certificate\n"); for(i=0; iu.certificate.ncert; i++) bs = bytesPrint(bs, be, "\t", m->u.certificate.certs[i], "\n"); break; case HCertificateRequest: bs = seprint(bs, be, "CertificateRequest\n"); bs = bytesPrint(bs, be, "\ttypes: ", m->u.certificateRequest.types, "\n"); bs = seprint(bs, be, "\tcertificateauthorities\n"); for(i=0; iu.certificateRequest.nca; i++) bs = bytesPrint(bs, be, "\t\t", m->u.certificateRequest.cas[i], "\n"); break; case HServerHelloDone: bs = seprint(bs, be, "ServerHelloDone\n"); break; case HClientKeyExchange: bs = seprint(bs, be, "HClientKeyExchange\n"); bs = bytesPrint(bs, be, "\tkey: ", m->u.clientKeyExchange.key, "\n"); break; case HFinished: bs = seprint(bs, be, "HFinished\n"); for(i=0; iu.finished.n; i++) bs = seprint(bs, be, "%.2x", m->u.finished.verify[i]); bs = seprint(bs, be, "\n"); break; } USED(bs); return buf; } static void tlsError(TlsConnection *c, int err, char *fmt, ...) { char msg[512]; va_list arg; va_start(arg, fmt); vseprint(msg, msg+sizeof(msg), fmt, arg); va_end(arg); if(c->trace) c->trace("tlsError: %s\n", msg); else if(c->erred) fprint(2, "double error: %r, %s", msg); else werrstr("tls: local %s", msg); c->erred = 1; fprint(c->ctl, "alert %d", err); } // commit to specific version number static int setVersion(TlsConnection *c, int version) { if(c->verset || version > MaxProtoVersion || version < MinProtoVersion) return -1; if(version > c->version) version = c->version; if(version == SSL3Version) { c->version = version; c->finished.n = SSL3FinishedLen; }else if(version == TLSVersion){ c->version = version; c->finished.n = TLSFinishedLen; }else return -1; c->verset = 1; return fprint(c->ctl, "version 0x%x", version); } // confirm that received Finished message matches the expected value static int finishedMatch(TlsConnection *c, Finished *f) { return memcmp(f->verify, c->finished.verify, f->n) == 0; } // free memory associated with TlsConnection struct // (but don't close the TLS channel itself) static void tlsConnectionFree(TlsConnection *c) { tlsSecClose(c->sec); freebytes(c->sid); freebytes(c->cert); memset(c, 0, sizeof(c)); free(c); } //================= cipher choices ======================== static int weakCipher[CipherMax] = { 1, /* TLS_NULL_WITH_NULL_NULL */ 1, /* TLS_RSA_WITH_NULL_MD5 */ 1, /* TLS_RSA_WITH_NULL_SHA */ 1, /* TLS_RSA_EXPORT_WITH_RC4_40_MD5 */ 0, /* TLS_RSA_WITH_RC4_128_MD5 */ 0, /* TLS_RSA_WITH_RC4_128_SHA */ 1, /* TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 */ 0, /* TLS_RSA_WITH_IDEA_CBC_SHA */ 1, /* TLS_RSA_EXPORT_WITH_DES40_CBC_SHA */ 0, /* TLS_RSA_WITH_DES_CBC_SHA */ 0, /* TLS_RSA_WITH_3DES_EDE_CBC_SHA */ 1, /* TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA */ 0, /* TLS_DH_DSS_WITH_DES_CBC_SHA */ 0, /* TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA */ 1, /* TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA */ 0, /* TLS_DH_RSA_WITH_DES_CBC_SHA */ 0, /* TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA */ 1, /* TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA */ 0, /* TLS_DHE_DSS_WITH_DES_CBC_SHA */ 0, /* TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA */ 1, /* TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA */ 0, /* TLS_DHE_RSA_WITH_DES_CBC_SHA */ 0, /* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA */ 1, /* TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 */ 1, /* TLS_DH_anon_WITH_RC4_128_MD5 */ 1, /* TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA */ 1, /* TLS_DH_anon_WITH_DES_CBC_SHA */ 1, /* TLS_DH_anon_WITH_3DES_EDE_CBC_SHA */ }; static int setAlgs(TlsConnection *c, int a) { int i; for(i = 0; i < nelem(cipherAlgs); i++){ if(cipherAlgs[i].tlsid == a){ c->enc = cipherAlgs[i].enc; c->digest = cipherAlgs[i].digest; c->nsecret = cipherAlgs[i].nsecret; if(c->nsecret > MaxKeyData) return 0; return 1; } } return 0; } static int okCipher(Ints *cv) { int weak, i, j, c; weak = 1; for(i = 0; i < cv->len; i++) { c = cv->data[i]; if(c >= CipherMax) weak = 0; else weak &= weakCipher[c]; for(j = 0; j < nelem(cipherAlgs); j++) if(cipherAlgs[j].ok && cipherAlgs[j].tlsid == c) return c; } if(weak) return -2; return -1; } static int okCompression(Bytes *cv) { int i, j, c; for(i = 0; i < cv->len; i++) { c = cv->data[i]; for(j = 0; j < nelem(compressors); j++) { if(compressors[j] == c) return c; } } return -1; } static Lock ciphLock; static int nciphers; static int initCiphers(void) { enum {MaxAlgF = 1024, MaxAlgs = 10}; char s[MaxAlgF], *flds[MaxAlgs]; int i, j, n, ok; lock(&ciphLock); if(nciphers){ unlock(&ciphLock); return nciphers; } j = open("#a/tls/encalgs", OREAD); if(j < 0){ werrstr("can't open #a/tls/encalgs: %r"); return 0; } n = read(j, s, MaxAlgF-1); close(j); if(n <= 0){ werrstr("nothing in #a/tls/encalgs: %r"); return 0; } s[n] = 0; n = getfields(s, flds, MaxAlgs, 1, " \t\r\n"); for(i = 0; i < nelem(cipherAlgs); i++){ ok = 0; for(j = 0; j < n; j++){ if(strcmp(cipherAlgs[i].enc, flds[j]) == 0){ ok = 1; break; } } cipherAlgs[i].ok = ok; } j = open("#a/tls/hashalgs", OREAD); if(j < 0){ werrstr("can't open #a/tls/hashalgs: %r"); return 0; } n = read(j, s, MaxAlgF-1); close(j); if(n <= 0){ werrstr("nothing in #a/tls/hashalgs: %r"); return 0; } s[n] = 0; n = getfields(s, flds, MaxAlgs, 1, " \t\r\n"); for(i = 0; i < nelem(cipherAlgs); i++){ ok = 0; for(j = 0; j < n; j++){ if(strcmp(cipherAlgs[i].digest, flds[j]) == 0){ ok = 1; break; } } cipherAlgs[i].ok &= ok; if(cipherAlgs[i].ok) nciphers++; } unlock(&ciphLock); return nciphers; } static Ints* makeciphers(void) { Ints *is; int i, j; is = newints(nciphers); j = 0; for(i = 0; i < nelem(cipherAlgs); i++){ if(cipherAlgs[i].ok) is->data[j++] = cipherAlgs[i].tlsid; } return is; } //================= security functions ======================== // given X.509 certificate, set up connection to factotum // for using corresponding private key static AuthRpc* factotum_rsa_open(uchar *cert, int certlen) { int afd; char *s; mpint *pub = nil; RSApub *rsapub; AuthRpc *rpc; // start talking to factotum if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0) return nil; if((rpc = auth_allocrpc(afd)) == nil){ close(afd); return nil; } s = "proto=rsa service=tls role=client"; if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){ factotum_rsa_close(rpc); return nil; } // roll factotum keyring around to match certificate rsapub = X509toRSApub(cert, certlen, nil, 0); while(1){ if(auth_rpc(rpc, "read", nil, 0) != ARok){ factotum_rsa_close(rpc); rpc = nil; goto done; } pub = strtomp(rpc->arg, nil, 16, nil); assert(pub != nil); if(mpcmp(pub,rsapub->n) == 0) break; } done: mpfree(pub); rsapubfree(rsapub); return rpc; } static mpint* factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher) { char *p; int rv; if((p = mptoa(cipher, 16, nil, 0)) == nil) return nil; rv = auth_rpc(rpc, "write", p, strlen(p)); free(p); if(rv != ARok || auth_rpc(rpc, "read", nil, 0) != ARok) return nil; mpfree(cipher); return strtomp(rpc->arg, nil, 16, nil); } static void factotum_rsa_close(AuthRpc*rpc) { if(!rpc) return; close(rpc->afd); auth_freerpc(rpc); } static void tlsPmd5(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1) { uchar ai[MD5dlen], tmp[MD5dlen]; int i, n; MD5state *s; // generate a1 s = hmac_md5(label, nlabel, key, nkey, nil, nil); s = hmac_md5(seed0, nseed0, key, nkey, nil, s); hmac_md5(seed1, nseed1, key, nkey, ai, s); while(nbuf > 0) { s = hmac_md5(ai, MD5dlen, key, nkey, nil, nil); s = hmac_md5(label, nlabel, key, nkey, nil, s); s = hmac_md5(seed0, nseed0, key, nkey, nil, s); hmac_md5(seed1, nseed1, key, nkey, tmp, s); n = MD5dlen; if(n > nbuf) n = nbuf; for(i = 0; i < n; i++) buf[i] ^= tmp[i]; buf += n; nbuf -= n; hmac_md5(ai, MD5dlen, key, nkey, tmp, nil); memmove(ai, tmp, MD5dlen); } } static void tlsPsha1(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1) { uchar ai[SHA1dlen], tmp[SHA1dlen]; int i, n; SHAstate *s; // generate a1 s = hmac_sha1(label, nlabel, key, nkey, nil, nil); s = hmac_sha1(seed0, nseed0, key, nkey, nil, s); hmac_sha1(seed1, nseed1, key, nkey, ai, s); while(nbuf > 0) { s = hmac_sha1(ai, SHA1dlen, key, nkey, nil, nil); s = hmac_sha1(label, nlabel, key, nkey, nil, s); s = hmac_sha1(seed0, nseed0, key, nkey, nil, s); hmac_sha1(seed1, nseed1, key, nkey, tmp, s); n = SHA1dlen; if(n > nbuf) n = nbuf; for(i = 0; i < n; i++) buf[i] ^= tmp[i]; buf += n; nbuf -= n; hmac_sha1(ai, SHA1dlen, key, nkey, tmp, nil); memmove(ai, tmp, SHA1dlen); } } // fill buf with md5(args)^sha1(args) static void tlsPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1) { int i; int nlabel = strlen(label); int n = (nkey + 1) >> 1; for(i = 0; i < nbuf; i++) buf[i] = 0; tlsPmd5(buf, nbuf, key, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1); tlsPsha1(buf, nbuf, key+nkey-n, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1); } /* * for setting server session id's */ static Lock sidLock; static long maxSid = 1; /* the keys are verified to have the same public components * and to function correctly with pkcs 1 encryption and decryption. */ static TlsSec* tlsSecInits(int cvers, uchar *csid, int ncsid, uchar *crandom, uchar *ssid, int *nssid, uchar *srandom) { TlsSec *sec = emalloc(sizeof(*sec)); USED(csid); USED(ncsid); // ignore csid for now memmove(sec->crandom, crandom, RandomSize); sec->clientVers = cvers; put32(sec->srandom, time(0)); genrandom(sec->srandom+4, RandomSize-4); memmove(srandom, sec->srandom, RandomSize); /* * make up a unique sid: use our pid, and and incrementing id * can signal no sid by setting nssid to 0. */ memset(ssid, 0, SidSize); put32(ssid, getpid()); lock(&sidLock); put32(ssid+4, maxSid++); unlock(&sidLock); *nssid = SidSize; return sec; } static int tlsSecSecrets(TlsSec *sec, int vers, uchar *epm, int nepm, uchar *kd, int nkd) { if(epm != nil){ if(setVers(sec, vers) < 0) goto Err; serverMasterSecret(sec, epm, nepm); }else if(sec->vers != vers){ werrstr("mismatched session versions"); goto Err; } setSecrets(sec, kd, nkd); return 0; Err: sec->ok = -1; return -1; } static TlsSec* tlsSecInitc(int cvers, uchar *crandom) { TlsSec *sec = emalloc(sizeof(*sec)); sec->clientVers = cvers; put32(sec->crandom, time(0)); genrandom(sec->crandom+4, RandomSize-4); memmove(crandom, sec->crandom, RandomSize); return sec; } static int tlsSecSecretc(TlsSec *sec, uchar *sid, int nsid, uchar *srandom, uchar *cert, int ncert, int vers, uchar **epm, int *nepm, uchar *kd, int nkd) { RSApub *pub; pub = nil; USED(sid); USED(nsid); memmove(sec->srandom, srandom, RandomSize); if(setVers(sec, vers) < 0) goto Err; pub = X509toRSApub(cert, ncert, nil, 0); if(pub == nil){ werrstr("invalid x509/rsa certificate"); goto Err; } if(clientMasterSecret(sec, pub, epm, nepm) < 0) goto Err; rsapubfree(pub); setSecrets(sec, kd, nkd); return 0; Err: if(pub != nil) rsapubfree(pub); sec->ok = -1; return -1; } static int tlsSecFinished(TlsSec *sec, MD5state md5, SHAstate sha1, uchar *fin, int nfin, int isclient) { if(sec->nfin != nfin){ sec->ok = -1; werrstr("invalid finished exchange"); return -1; } md5.malloced = 0; sha1.malloced = 0; (*sec->setFinished)(sec, md5, sha1, fin, isclient); return 1; } static void tlsSecOk(TlsSec *sec) { if(sec->ok == 0) sec->ok = 1; } static void tlsSecKill(TlsSec *sec) { if(!sec) return; factotum_rsa_close(sec->rpc); sec->ok = -1; } static void tlsSecClose(TlsSec *sec) { if(!sec) return; factotum_rsa_close(sec->rpc); free(sec->server); free(sec); } static int setVers(TlsSec *sec, int v) { if(v == SSL3Version){ sec->setFinished = sslSetFinished; sec->nfin = SSL3FinishedLen; sec->prf = sslPRF; }else if(v == TLSVersion){ sec->setFinished = tlsSetFinished; sec->nfin = TLSFinishedLen; sec->prf = tlsPRF; }else{ werrstr("invalid version"); return -1; } sec->vers = v; return 0; } /* * generate secret keys from the master secret. * * different crypto selections will require different amounts * of key expansion and use of key expansion data, * but it's all generated using the same function. */ static void setSecrets(TlsSec *sec, uchar *kd, int nkd) { (*sec->prf)(kd, nkd, sec->sec, MasterSecretSize, "key expansion", sec->srandom, RandomSize, sec->crandom, RandomSize); } /* * set the master secret from the pre-master secret. */ static void setMasterSecret(TlsSec *sec, Bytes *pm) { (*sec->prf)(sec->sec, MasterSecretSize, pm->data, MasterSecretSize, "master secret", sec->crandom, RandomSize, sec->srandom, RandomSize); } static void serverMasterSecret(TlsSec *sec, uchar *epm, int nepm) { Bytes *pm; pm = pkcs1_decrypt(sec, epm, nepm); // if the client messed up, just continue as if everything is ok, // to prevent attacks to check for correctly formatted messages. // Hence the fprint(2,) can't be replaced by tlsError(), which sends an Alert msg to the client. if(sec->ok < 0 || pm == nil || get16(pm->data) != sec->clientVers){ fprint(2, "serverMasterSecret failed ok=%d pm=%p pmvers=%x cvers=%x nepm=%d\n", sec->ok, pm, pm ? get16(pm->data) : -1, sec->clientVers, nepm); sec->ok = -1; if(pm != nil) freebytes(pm); pm = newbytes(MasterSecretSize); genrandom(pm->data, MasterSecretSize); } setMasterSecret(sec, pm); memset(pm->data, 0, pm->len); freebytes(pm); } static int clientMasterSecret(TlsSec *sec, RSApub *pub, uchar **epm, int *nepm) { Bytes *pm, *key; pm = newbytes(MasterSecretSize); put16(pm->data, sec->clientVers); genrandom(pm->data+2, MasterSecretSize - 2); setMasterSecret(sec, pm); key = pkcs1_encrypt(pm, pub, 2); memset(pm->data, 0, pm->len); freebytes(pm); if(key == nil){ werrstr("tls pkcs1_encrypt failed"); return -1; } *nepm = key->len; *epm = malloc(*nepm); if(*epm == nil){ freebytes(key); werrstr("out of memory"); return -1; } memmove(*epm, key->data, *nepm); freebytes(key); return 1; } static void sslSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient) { DigestState *s; uchar h0[MD5dlen], h1[SHA1dlen], pad[48]; char *label; if(isClient) label = "CLNT"; else label = "SRVR"; md5((uchar*)label, 4, nil, &hsmd5); md5(sec->sec, MasterSecretSize, nil, &hsmd5); memset(pad, 0x36, 48); md5(pad, 48, nil, &hsmd5); md5(nil, 0, h0, &hsmd5); memset(pad, 0x5C, 48); s = md5(sec->sec, MasterSecretSize, nil, nil); s = md5(pad, 48, nil, s); md5(h0, MD5dlen, finished, s); sha1((uchar*)label, 4, nil, &hssha1); sha1(sec->sec, MasterSecretSize, nil, &hssha1); memset(pad, 0x36, 40); sha1(pad, 40, nil, &hssha1); sha1(nil, 0, h1, &hssha1); memset(pad, 0x5C, 40); s = sha1(sec->sec, MasterSecretSize, nil, nil); s = sha1(pad, 40, nil, s); sha1(h1, SHA1dlen, finished + MD5dlen, s); } // fill "finished" arg with md5(args)^sha1(args) static void tlsSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient) { uchar h0[MD5dlen], h1[SHA1dlen]; char *label; // get current hash value, but allow further messages to be hashed in md5(nil, 0, h0, &hsmd5); sha1(nil, 0, h1, &hssha1); if(isClient) label = "client finished"; else label = "server finished"; tlsPRF(finished, TLSFinishedLen, sec->sec, MasterSecretSize, label, h0, MD5dlen, h1, SHA1dlen); } static void sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1) { DigestState *s; uchar sha1dig[SHA1dlen], md5dig[MD5dlen], tmp[26]; int i, n, len; USED(label); len = 1; while(nbuf > 0){ if(len > 26) return; for(i = 0; i < len; i++) tmp[i] = 'A' - 1 + len; s = sha1(tmp, len, nil, nil); s = sha1(key, nkey, nil, s); s = sha1(seed0, nseed0, nil, s); sha1(seed1, nseed1, sha1dig, s); s = md5(key, nkey, nil, nil); md5(sha1dig, SHA1dlen, md5dig, s); n = MD5dlen; if(n > nbuf) n = nbuf; memmove(buf, md5dig, n); buf += n; nbuf -= n; len++; } } static mpint* bytestomp(Bytes* bytes) { mpint* ans; ans = betomp(bytes->data, bytes->len, nil); return ans; } /* * Convert mpint* to Bytes, putting high order byte first. */ static Bytes* mptobytes(mpint* big) { int n, m; uchar *a; Bytes* ans; n = (mpsignif(big)+7)/8; m = mptobe(big, nil, n, &a); ans = makebytes(a, m); return ans; } // Do RSA computation on block according to key, and pad // result on left with zeros to make it modlen long. static Bytes* rsacomp(Bytes* block, RSApub* key, int modlen) { mpint *x, *y; Bytes *a, *ybytes; int ylen; x = bytestomp(block); y = rsaencrypt(key, x, nil); mpfree(x); ybytes = mptobytes(y); ylen = ybytes->len; if(ylen < modlen) { a = newbytes(modlen); memset(a->data, 0, modlen-ylen); memmove(a->data+modlen-ylen, ybytes->data, ylen); freebytes(ybytes); ybytes = a; } else if(ylen > modlen) { // assume it has leading zeros (mod should make it so) a = newbytes(modlen); memmove(a->data, ybytes->data, modlen); freebytes(ybytes); ybytes = a; } mpfree(y); return ybytes; } // encrypt data according to PKCS#1, /lib/rfc/rfc2437 9.1.2.1 static Bytes* pkcs1_encrypt(Bytes* data, RSApub* key, int blocktype) { Bytes *pad, *eb, *ans; int i, dlen, padlen, modlen; modlen = (mpsignif(key->n)+7)/8; dlen = data->len; if(modlen < 12 || dlen > modlen - 11) return nil; padlen = modlen - 3 - dlen; pad = newbytes(padlen); genrandom(pad->data, padlen); for(i = 0; i < padlen; i++) { if(blocktype == 0) pad->data[i] = 0; else if(blocktype == 1) pad->data[i] = 255; else if(pad->data[i] == 0) pad->data[i] = 1; } eb = newbytes(modlen); eb->data[0] = 0; eb->data[1] = blocktype; memmove(eb->data+2, pad->data, padlen); eb->data[padlen+2] = 0; memmove(eb->data+padlen+3, data->data, dlen); ans = rsacomp(eb, key, modlen); freebytes(eb); freebytes(pad); return ans; } // decrypt data according to PKCS#1, with given key. // expect a block type of 2. static Bytes* pkcs1_decrypt(TlsSec *sec, uchar *epm, int nepm) { Bytes *eb, *ans = nil; int i, modlen; mpint *x, *y; modlen = (mpsignif(sec->rsapub->n)+7)/8; if(nepm != modlen) return nil; x = betomp(epm, nepm, nil); y = factotum_rsa_decrypt(sec->rpc, x); if(y == nil) return nil; eb = mptobytes(y); if(eb->len < modlen){ // pad on left with zeros ans = newbytes(modlen); memset(ans->data, 0, modlen-eb->len); memmove(ans->data+modlen-eb->len, eb->data, eb->len); freebytes(eb); eb = ans; } if(eb->data[0] == 0 && eb->data[1] == 2) { for(i = 2; i < modlen; i++) if(eb->data[i] == 0) break; if(i < modlen - 1) ans = makebytes(eb->data+i+1, modlen-(i+1)); } freebytes(eb); return ans; } //================= general utility functions ======================== static void * emalloc(int n) { void *p; if(n==0) n=1; p = malloc(n); if(p == nil){ exits("out of memory"); } memset(p, 0, n); return p; } static void * erealloc(void *ReallocP, int ReallocN) { if(ReallocN == 0) ReallocN = 1; if(!ReallocP) ReallocP = emalloc(ReallocN); else if(!(ReallocP = realloc(ReallocP, ReallocN))){ exits("out of memory"); } return(ReallocP); } static void put32(uchar *p, u32int x) { p[0] = x>>24; p[1] = x>>16; p[2] = x>>8; p[3] = x; } static void put24(uchar *p, int x) { p[0] = x>>16; p[1] = x>>8; p[2] = x; } static void put16(uchar *p, int x) { p[0] = x>>8; p[1] = x; } static u32int get32(uchar *p) { return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]; } static int get24(uchar *p) { return (p[0]<<16)|(p[1]<<8)|p[2]; } static int get16(uchar *p) { return (p[0]<<8)|p[1]; } /* ANSI offsetof() */ #define OFFSET(x, s) ((int)(&(((s*)0)->x))) /* * malloc and return a new Bytes structure capable of * holding len bytes. (len >= 0) * Used to use crypt_malloc, which aborts if malloc fails. */ static Bytes* newbytes(int len) { Bytes* ans; ans = (Bytes*)malloc(OFFSET(data[0], Bytes) + len); ans->len = len; return ans; } /* * newbytes(len), with data initialized from buf */ static Bytes* makebytes(uchar* buf, int len) { Bytes* ans; ans = newbytes(len); memmove(ans->data, buf, len); return ans; } static void freebytes(Bytes* b) { if(b != nil) free(b); } /* len is number of ints */ static Ints* newints(int len) { Ints* ans; ans = (Ints*)malloc(OFFSET(data[0], Ints) + len*sizeof(int)); ans->len = len; return ans; } static Ints* makeints(int* buf, int len) { Ints* ans; ans = newints(len); if(len > 0) memmove(ans->data, buf, len*sizeof(int)); return ans; } static void freeints(Ints* b) { if(b != nil) free(b); } drawterm-20170818/libsec/x509.c000066400000000000000000001420751314554504700157460ustar00rootroot00000000000000#include #include #include #include typedef DigestState*(*DigestFun)(uchar*,ulong,uchar*,DigestState*); /* ANSI offsetof, backwards. */ #define OFFSETOF(a, b) offsetof(b, a) /*=============================================================*/ /* general ASN1 declarations and parsing * * For now, this is used only for extracting the key from an * X509 certificate, so the entire collection is hidden. But * someday we should probably make the functions visible and * give them their own man page. */ typedef struct Elem Elem; typedef struct Tag Tag; typedef struct Value Value; typedef struct Bytes Bytes; typedef struct Ints Ints; typedef struct Bits Bits; typedef struct Elist Elist; /* tag classes */ #define Universal 0 #define Context 0x80 /* universal tags */ #define BOOLEAN 1 #define INTEGER 2 #define BIT_STRING 3 #define OCTET_STRING 4 #define NULLTAG 5 #define OBJECT_ID 6 #define ObjectDescriptor 7 #define EXTERNAL 8 #define REAL 9 #define ENUMERATED 10 #define EMBEDDED_PDV 11 #define SEQUENCE 16 /* also SEQUENCE OF */ #define SETOF 17 /* also SETOF OF */ #define NumericString 18 #define PrintableString 19 #define TeletexString 20 #define VideotexString 21 #define IA5String 22 #define UTCTime 23 #define GeneralizedTime 24 #define GraphicString 25 #define VisibleString 26 #define GeneralString 27 #define UniversalString 28 #define BMPString 30 struct Bytes { int len; uchar data[1]; }; struct Ints { int len; int data[1]; }; struct Bits { int len; /* number of bytes */ int unusedbits; /* unused bits in last byte */ uchar data[1]; /* most-significant bit first */ }; struct Tag { int class; int num; }; enum { VBool, VInt, VOctets, VBigInt, VReal, VOther, VBitString, VNull, VEOC, VObjId, VString, VSeq, VSet }; struct Value { int tag; /* VBool, etc. */ union { int boolval; int intval; Bytes* octetsval; Bytes* bigintval; Bytes* realval; /* undecoded; hardly ever used */ Bytes* otherval; Bits* bitstringval; Ints* objidval; char* stringval; Elist* seqval; Elist* setval; } u; /* (Don't use anonymous unions, for ease of porting) */ }; struct Elem { Tag tag; Value val; }; struct Elist { Elist* tl; Elem hd; }; /* decoding errors */ enum { ASN_OK, ASN_ESHORT, ASN_ETOOBIG, ASN_EVALLEN, ASN_ECONSTR, ASN_EPRIM, ASN_EINVAL, ASN_EUNIMPL }; /* here are the functions to consider making extern someday */ static Bytes* newbytes(int len); static Bytes* makebytes(uchar* buf, int len); static void freebytes(Bytes* b); static Bytes* catbytes(Bytes* b1, Bytes* b2); static Ints* newints(int len); static Ints* makeints(int* buf, int len); static void freeints(Ints* b); static Bits* newbits(int len); static Bits* makebits(uchar* buf, int len, int unusedbits); static void freebits(Bits* b); static Elist* mkel(Elem e, Elist* tail); static void freeelist(Elist* el); static int elistlen(Elist* el); static int is_seq(Elem* pe, Elist** pseq); static int is_set(Elem* pe, Elist** pset); static int is_int(Elem* pe, int* pint); static int is_bigint(Elem* pe, Bytes** pbigint); static int is_bitstring(Elem* pe, Bits** pbits); static int is_octetstring(Elem* pe, Bytes** poctets); static int is_oid(Elem* pe, Ints** poid); static int is_string(Elem* pe, char** pstring); static int is_time(Elem* pe, char** ptime); static int decode(uchar* a, int alen, Elem* pelem); static int decode_seq(uchar* a, int alen, Elist** pelist); static int decode_value(uchar* a, int alen, int kind, int isconstr, Value* pval); static int encode(Elem e, Bytes** pbytes); static int oid_lookup(Ints* o, Ints** tab); static void freevalfields(Value* v); static mpint *asn1mpint(Elem *e); #define TAG_MASK 0x1F #define CONSTR_MASK 0x20 #define CLASS_MASK 0xC0 #define MAXOBJIDLEN 20 static int ber_decode(uchar** pp, uchar* pend, Elem* pelem); static int tag_decode(uchar** pp, uchar* pend, Tag* ptag, int* pisconstr); static int length_decode(uchar** pp, uchar* pend, int* plength); static int value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval); static int int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint); static int uint7_decode(uchar** pp, uchar* pend, int* pint); static int octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes); static int seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist); static int enc(uchar** pp, Elem e, int lenonly); static int val_enc(uchar** pp, Elem e, int *pconstr, int lenonly); static void uint7_enc(uchar** pp, int num, int lenonly); static void int_enc(uchar** pp, int num, int unsgned, int lenonly); static void * emalloc(int n) { void *p; if(n==0) n=1; p = malloc(n); if(p == nil){ exits("out of memory"); } memset(p, 0, n); return p; } static char* estrdup(char *s) { char *d, *d0; if(!s) return 0; d = d0 = emalloc(strlen(s)+1); while(*d++ = *s++) ; return d0; } /* * Decode a[0..len] as a BER encoding of an ASN1 type. * The return value is one of ASN_OK, etc. * Depending on the error, the returned elem may or may not * be nil. */ static int decode(uchar* a, int alen, Elem* pelem) { uchar* p = a; return ber_decode(&p, &a[alen], pelem); } /* * Like decode, but continue decoding after first element * of array ends. */ static int decode_seq(uchar* a, int alen, Elist** pelist) { uchar* p = a; return seq_decode(&p, &a[alen], -1, 1, pelist); } /* * Decode the whole array as a BER encoding of an ASN1 value, * (i.e., the part after the tag and length). * Assume the value is encoded as universal tag "kind". * The constr arg is 1 if the value is constructed, 0 if primitive. * If there's an error, the return string will contain the error. * Depending on the error, the returned value may or may not * be nil. */ static int decode_value(uchar* a, int alen, int kind, int isconstr, Value* pval) { uchar* p = a; return value_decode(&p, &a[alen], alen, kind, isconstr, pval); } /* * All of the following decoding routines take arguments: * uchar **pp; * uchar *pend; * Where parsing is supposed to start at **pp, and when parsing * is done, *pp is updated to point at next char to be parsed. * The pend pointer is just past end of string; an error should * be returned parsing hasn't finished by then. * * The returned int is ASN_OK if all went fine, else ASN_ESHORT, etc. * The remaining argument(s) are pointers to where parsed entity goes. */ /* Decode an ASN1 'Elem' (tag, length, value) */ static int ber_decode(uchar** pp, uchar* pend, Elem* pelem) { int err; int isconstr; int length; Tag tag; Value val; err = tag_decode(pp, pend, &tag, &isconstr); if(err == ASN_OK) { err = length_decode(pp, pend, &length); if(err == ASN_OK) { if(tag.class == Universal) err = value_decode(pp, pend, length, tag.num, isconstr, &val); else err = value_decode(pp, pend, length, OCTET_STRING, 0, &val); if(err == ASN_OK) { pelem->tag = tag; pelem->val = val; } } } return err; } /* Decode a tag field */ static int tag_decode(uchar** pp, uchar* pend, Tag* ptag, int* pisconstr) { int err; int v; uchar* p; err = ASN_OK; p = *pp; if(pend-p >= 2) { v = *p++; ptag->class = v&CLASS_MASK; if(v&CONSTR_MASK) *pisconstr = 1; else *pisconstr = 0; v &= TAG_MASK; if(v == TAG_MASK) err = uint7_decode(&p, pend, &v); ptag->num = v; } else err = ASN_ESHORT; *pp = p; return err; } /* Decode a length field */ static int length_decode(uchar** pp, uchar* pend, int* plength) { int err; int num; int v; uchar* p; err = ASN_OK; num = 0; p = *pp; if(p < pend) { v = *p++; if(v&0x80) err = int_decode(&p, pend, v&0x7F, 1, &num); else if(v == 0x80) num = -1; else num = v; } else err = ASN_ESHORT; *pp = p; *plength = num; return err; } /* Decode a value field */ static int value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval) { int err; Bytes* va; int num; int bitsunused; int subids[MAXOBJIDLEN]; int isubid; Elist* vl; uchar* p; uchar* pe; err = ASN_OK; p = *pp; if(length == -1) { /* "indefinite" length spec */ if(!isconstr) err = ASN_EINVAL; } else if(p + length > pend) err = ASN_EVALLEN; if(err != ASN_OK) return err; switch(kind) { case 0: /* marker for end of indefinite constructions */ if(length == 0) pval->tag = VNull; else err = ASN_EINVAL; break; case BOOLEAN: if(isconstr) err = ASN_ECONSTR; else if(length != 1) err = ASN_EVALLEN; else { pval->tag = VBool; pval->u.boolval = (*p++ != 0); } break; case INTEGER: case ENUMERATED: if(isconstr) err = ASN_ECONSTR; else if(length <= 4) { err = int_decode(&p, pend, length, 0, &num); if(err == ASN_OK) { pval->tag = VInt; pval->u.intval = num; } } else { pval->tag = VBigInt; pval->u.bigintval = makebytes(p, length); p += length; } break; case BIT_STRING: pval->tag = VBitString; if(isconstr) { if(length == -1 && p + 2 <= pend && *p == 0 && *(p+1) ==0) { pval->u.bitstringval = makebits(0, 0, 0); p += 2; } else /* TODO: recurse and concat results */ err = ASN_EUNIMPL; } else { if(length < 2) { if(length == 1 && *p == 0) { pval->u.bitstringval = makebits(0, 0, 0); p++; } else err = ASN_EINVAL; } else { bitsunused = *p; if(bitsunused > 7) err = ASN_EINVAL; else if(length > 0x0FFFFFFF) err = ASN_ETOOBIG; else { pval->u.bitstringval = makebits(p+1, length-1, bitsunused); p += length; } } } break; case OCTET_STRING: case ObjectDescriptor: err = octet_decode(&p, pend, length, isconstr, &va); if(err == ASN_OK) { pval->tag = VOctets; pval->u.octetsval = va; } break; case NULLTAG: if(isconstr) err = ASN_ECONSTR; else if(length != 0) err = ASN_EVALLEN; else pval->tag = VNull; break; case OBJECT_ID: if(isconstr) err = ASN_ECONSTR; else if(length == 0) err = ASN_EVALLEN; else { isubid = 0; pe = p+length; while(p < pe && isubid < MAXOBJIDLEN) { err = uint7_decode(&p, pend, &num); if(err != ASN_OK) break; if(isubid == 0) { subids[isubid++] = num / 40; subids[isubid++] = num % 40; } else subids[isubid++] = num; } if(err == ASN_OK) { if(p != pe) err = ASN_EVALLEN; else { pval->tag = VObjId; pval->u.objidval = makeints(subids, isubid); } } } break; case EXTERNAL: case EMBEDDED_PDV: /* TODO: parse this internally */ if(p+length > pend) err = ASN_EVALLEN; else { pval->tag = VOther; pval->u.otherval = makebytes(p, length); p += length; } break; case REAL: /* Let the application decode */ if(isconstr) err = ASN_ECONSTR; else if(p+length > pend) err = ASN_EVALLEN; else { pval->tag = VReal; pval->u.realval = makebytes(p, length); p += length; } break; case SEQUENCE: err = seq_decode(&p, pend, length, isconstr, &vl); if(err == ASN_OK) { pval->tag = VSeq ; pval->u.seqval = vl; } break; case SETOF: err = seq_decode(&p, pend, length, isconstr, &vl); if(err == ASN_OK) { pval->tag = VSet; pval->u.setval = vl; } break; case NumericString: case PrintableString: case TeletexString: case VideotexString: case IA5String: case UTCTime: case GeneralizedTime: case GraphicString: case VisibleString: case GeneralString: case UniversalString: case BMPString: /* TODO: figure out when character set conversion is necessary */ err = octet_decode(&p, pend, length, isconstr, &va); if(err == ASN_OK) { pval->tag = VString; pval->u.stringval = (char*)emalloc(va->len+1); memmove(pval->u.stringval, va->data, va->len); pval->u.stringval[va->len] = 0; free(va); } break; default: if(p+length > pend) err = ASN_EVALLEN; else { pval->tag = VOther; pval->u.otherval = makebytes(p, length); p += length; } break; } *pp = p; return err; } /* * Decode an int in format where count bytes are * concatenated to form value. * Although ASN1 allows any size integer, we return * an error if the result doesn't fit in a 32-bit int. * If unsgned is not set, make sure to propagate sign bit. */ static int int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint) { int err; int num; uchar* p; p = *pp; err = ASN_OK; num = 0; if(p+count <= pend) { if((count > 4) || (unsgned && count == 4 && (*p&0x80))) err = ASN_ETOOBIG; else { if(!unsgned && count > 0 && count < 4 && (*p&0x80)) num = -1; // set all bits, initially while(count--) num = (num << 8)|(*p++); } } else err = ASN_ESHORT; *pint = num; *pp = p; return err; } /* * Decode an unsigned int in format where each * byte except last has high bit set, and remaining * seven bits of each byte are concatenated to form value. * Although ASN1 allows any size integer, we return * an error if the result doesn't fit in a 32 bit int. */ static int uint7_decode(uchar** pp, uchar* pend, int* pint) { int err; int num; int more; int v; uchar* p; p = *pp; err = ASN_OK; num = 0; more = 1; while(more && p < pend) { v = *p++; if(num&0x7F000000) { err = ASN_ETOOBIG; break; } num <<= 7; more = v&0x80; num |= (v&0x7F); } if(p == pend) err = ASN_ESHORT; *pint = num; *pp = p; return err; } /* * Decode an octet string, recursively if isconstr. * We've already checked that length==-1 implies isconstr==1, * and otherwise that specified length fits within (*pp..pend) */ static int octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes) { int err; uchar* p; Bytes* ans; Bytes* newans; uchar* pstart; uchar* pold; Elem elem; err = ASN_OK; p = *pp; ans = nil; if(length >= 0 && !isconstr) { ans = makebytes(p, length); p += length; } else { /* constructed, either definite or indefinite length */ pstart = p; for(;;) { if(length >= 0 && p >= pstart + length) { if(p != pstart + length) err = ASN_EVALLEN; break; } pold = p; err = ber_decode(&p, pend, &elem); if(err != ASN_OK) break; switch(elem.val.tag) { case VOctets: newans = catbytes(ans, elem.val.u.octetsval); freebytes(ans); ans = newans; break; case VEOC: if(length != -1) { p = pold; err = ASN_EINVAL; } goto cloop_done; default: p = pold; err = ASN_EINVAL; goto cloop_done; } } cloop_done: ; } *pp = p; *pbytes = ans; return err; } /* * Decode a sequence or set. * We've already checked that length==-1 implies isconstr==1, * and otherwise that specified length fits within (*p..pend) */ static int seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist) { int err; uchar* p; uchar* pstart; uchar* pold; Elist* ans; Elem elem; Elist* lve; Elist* lveold; err = ASN_OK; ans = nil; p = *pp; if(!isconstr) err = ASN_EPRIM; else { /* constructed, either definite or indefinite length */ lve = nil; pstart = p; for(;;) { if(length >= 0 && p >= pstart + length) { if(p != pstart + length) err = ASN_EVALLEN; break; } pold = p; err = ber_decode(&p, pend, &elem); if(err != ASN_OK) break; if(elem.val.tag == VEOC) { if(length != -1) { p = pold; err = ASN_EINVAL; } break; } else lve = mkel(elem, lve); } if(err == ASN_OK) { /* reverse back to original order */ while(lve != nil) { lveold = lve; lve = lve->tl; lveold->tl = ans; ans = lveold; } } } *pp = p; *pelist = ans; return err; } /* * Encode e by BER rules, putting answer in *pbytes. * This is done by first calling enc with lenonly==1 * to get the length of the needed buffer, * then allocating the buffer and using enc again to fill it up. */ static int encode(Elem e, Bytes** pbytes) { uchar* p; Bytes* ans; int err; uchar uc; p = &uc; err = enc(&p, e, 1); if(err == ASN_OK) { ans = newbytes(p-&uc); p = ans->data; err = enc(&p, e, 0); *pbytes = ans; } return err; } /* * The various enc functions take a pointer to a pointer * into a buffer, and encode their entity starting there, * updating the pointer afterwards. * If lenonly is 1, only the pointer update is done, * allowing enc to be called first to calculate the needed * buffer length. * If lenonly is 0, it is assumed that the answer will fit. */ static int enc(uchar** pp, Elem e, int lenonly) { int err; int vlen; int constr; Tag tag; int v; int ilen; uchar* p; uchar* psave; p = *pp; err = val_enc(&p, e, &constr, 1); if(err != ASN_OK) return err; vlen = p - *pp; p = *pp; tag = e.tag; v = tag.class|constr; if(tag.num < 31) { if(!lenonly) *p = (v|tag.num); p++; } else { if(!lenonly) *p = (v|31); p++; if(tag.num < 0) return ASN_EINVAL; uint7_enc(&p, tag.num, lenonly); } if(vlen < 0x80) { if(!lenonly) *p = vlen; p++; } else { psave = p; int_enc(&p, vlen, 1, 1); ilen = p-psave; p = psave; if(!lenonly) { *p++ = (0x80 | ilen); int_enc(&p, vlen, 1, 0); } else p += 1 + ilen; } if(!lenonly) val_enc(&p, e, &constr, 0); else p += vlen; *pp = p; return err; } static int val_enc(uchar** pp, Elem e, int *pconstr, int lenonly) { int err; uchar* p; int kind; int cl; int v; Bytes* bb = nil; Bits* bits; Ints* oid; int k; Elist* el; char* s; p = *pp; err = ASN_OK; kind = e.tag.num; cl = e.tag.class; *pconstr = 0; if(cl != Universal) { switch(e.val.tag) { case VBool: kind = BOOLEAN; break; case VInt: kind = INTEGER; break; case VBigInt: kind = INTEGER; break; case VOctets: kind = OCTET_STRING; break; case VReal: kind = REAL; break; case VOther: kind = OCTET_STRING; break; case VBitString: kind = BIT_STRING; break; case VNull: kind = NULLTAG; break; case VObjId: kind = OBJECT_ID; break; case VString: kind = UniversalString; break; case VSeq: kind = SEQUENCE; break; case VSet: kind = SETOF; break; } } switch(kind) { case BOOLEAN: if(is_int(&e, &v)) { if(v != 0) v = 255; int_enc(&p, v, 1, lenonly); } else err = ASN_EINVAL; break; case INTEGER: case ENUMERATED: if(is_int(&e, &v)) int_enc(&p, v, 0, lenonly); else { if(is_bigint(&e, &bb)) { if(!lenonly) memmove(p, bb->data, bb->len); p += bb->len; } else err = ASN_EINVAL; } break; case BIT_STRING: if(is_bitstring(&e, &bits)) { if(bits->len == 0) { if(!lenonly) *p = 0; p++; } else { v = bits->unusedbits; if(v < 0 || v > 7) err = ASN_EINVAL; else { if(!lenonly) { *p = v; memmove(p+1, bits->data, bits->len); } p += 1 + bits->len; } } } else err = ASN_EINVAL; break; case OCTET_STRING: case ObjectDescriptor: case EXTERNAL: case REAL: case EMBEDDED_PDV: bb = nil; switch(e.val.tag) { case VOctets: bb = e.val.u.octetsval; break; case VReal: bb = e.val.u.realval; break; case VOther: bb = e.val.u.otherval; break; } if(bb != nil) { if(!lenonly) memmove(p, bb->data, bb->len); p += bb->len; } else err = ASN_EINVAL; break; case NULLTAG: break; case OBJECT_ID: if(is_oid(&e, &oid)) { for(k = 0; k < oid->len; k++) { v = oid->data[k]; if(k == 0) { v *= 40; if(oid->len > 1) v += oid->data[++k]; } uint7_enc(&p, v, lenonly); } } else err = ASN_EINVAL; break; case SEQUENCE: case SETOF: el = nil; if(e.val.tag == VSeq) el = e.val.u.seqval; else if(e.val.tag == VSet) el = e.val.u.setval; else err = ASN_EINVAL; if(el != nil) { *pconstr = CONSTR_MASK; for(; el != nil; el = el->tl) { err = enc(&p, el->hd, lenonly); if(err != ASN_OK) break; } } break; case NumericString: case PrintableString: case TeletexString: case VideotexString: case IA5String: case UTCTime: case GeneralizedTime: case GraphicString: case VisibleString: case GeneralString: case UniversalString: case BMPString: if(e.val.tag == VString) { s = e.val.u.stringval; if(s != nil) { v = strlen(s); if(!lenonly) memmove(p, s, v); p += v; } } else err = ASN_EINVAL; break; default: err = ASN_EINVAL; } *pp = p; return err; } /* * Encode num as unsigned 7 bit values with top bit 1 on all bytes * except last, only putting in bytes if !lenonly. */ static void uint7_enc(uchar** pp, int num, int lenonly) { int n; int v; int k; uchar* p; p = *pp; n = 1; v = num >> 7; while(v > 0) { v >>= 7; n++; } if(lenonly) p += n; else { for(k = (n - 1)*7; k > 0; k -= 7) *p++= ((num >> k)|0x80); *p++ = (num&0x7F); } *pp = p; } /* * Encode num as unsigned or signed integer, * only putting in bytes if !lenonly. * Encoding is length followed by bytes to concatenate. */ static void int_enc(uchar** pp, int num, int unsgned, int lenonly) { int v; int n; int prevv; int k; uchar* p; p = *pp; v = num; if(v < 0) v = -(v + 1); n = 1; prevv = v; v >>= 8; while(v > 0) { prevv = v; v >>= 8; n++; } if(!unsgned && (prevv&0x80)) n++; if(lenonly) p += n; else { for(k = (n - 1)*8; k >= 0; k -= 8) *p++ = (num >> k); } *pp = p; } static int ints_eq(Ints* a, Ints* b) { int alen; int i; alen = a->len; if(alen != b->len) return 0; for(i = 0; i < alen; i++) if(a->data[i] != b->data[i]) return 0; return 1; } /* * Look up o in tab (which must have nil entry to terminate). * Return index of matching entry, or -1 if none. */ static int oid_lookup(Ints* o, Ints** tab) { int i; for(i = 0; tab[i] != nil; i++) if(ints_eq(o, tab[i])) return i; return -1; } /* * Return true if *pe is a SEQUENCE, and set *pseq to * the value of the sequence if so. */ static int is_seq(Elem* pe, Elist** pseq) { if(pe->tag.class == Universal && pe->tag.num == SEQUENCE && pe->val.tag == VSeq) { *pseq = pe->val.u.seqval; return 1; } return 0; } static int is_set(Elem* pe, Elist** pset) { if(pe->tag.class == Universal && pe->tag.num == SETOF && pe->val.tag == VSet) { *pset = pe->val.u.setval; return 1; } return 0; } static int is_int(Elem* pe, int* pint) { if(pe->tag.class == Universal) { if(pe->tag.num == INTEGER && pe->val.tag == VInt) { *pint = pe->val.u.intval; return 1; } else if(pe->tag.num == BOOLEAN && pe->val.tag == VBool) { *pint = pe->val.u.boolval; return 1; } } return 0; } /* * for convience, all VInt's are readable via this routine, * as well as all VBigInt's */ static int is_bigint(Elem* pe, Bytes** pbigint) { int v, n, i; if(pe->tag.class == Universal && pe->tag.num == INTEGER) { if(pe->val.tag == VBigInt) *pbigint = pe->val.u.bigintval; else if(pe->val.tag == VInt){ v = pe->val.u.intval; for(n = 1; n < 4; n++) if((1 << (8 * n)) > v) break; *pbigint = newbytes(n); for(i = 0; i < n; i++) (*pbigint)->data[i] = (v >> ((n - 1 - i) * 8)); }else return 0; return 1; } return 0; } static int is_bitstring(Elem* pe, Bits** pbits) { if(pe->tag.class == Universal && pe->tag.num == BIT_STRING && pe->val.tag == VBitString) { *pbits = pe->val.u.bitstringval; return 1; } return 0; } static int is_octetstring(Elem* pe, Bytes** poctets) { if(pe->tag.class == Universal && pe->tag.num == OCTET_STRING && pe->val.tag == VOctets) { *poctets = pe->val.u.octetsval; return 1; } return 0; } static int is_oid(Elem* pe, Ints** poid) { if(pe->tag.class == Universal && pe->tag.num == OBJECT_ID && pe->val.tag == VObjId) { *poid = pe->val.u.objidval; return 1; } return 0; } static int is_string(Elem* pe, char** pstring) { if(pe->tag.class == Universal) { switch(pe->tag.num) { case NumericString: case PrintableString: case TeletexString: case VideotexString: case IA5String: case GraphicString: case VisibleString: case GeneralString: case UniversalString: case BMPString: if(pe->val.tag == VString) { *pstring = pe->val.u.stringval; return 1; } } } return 0; } static int is_time(Elem* pe, char** ptime) { if(pe->tag.class == Universal && (pe->tag.num == UTCTime || pe->tag.num == GeneralizedTime) && pe->val.tag == VString) { *ptime = pe->val.u.stringval; return 1; } return 0; } /* * malloc and return a new Bytes structure capable of * holding len bytes. (len >= 0) */ static Bytes* newbytes(int len) { Bytes* ans; ans = (Bytes*)emalloc(OFFSETOF(data[0], Bytes) + len); ans->len = len; return ans; } /* * newbytes(len), with data initialized from buf */ static Bytes* makebytes(uchar* buf, int len) { Bytes* ans; ans = newbytes(len); memmove(ans->data, buf, len); return ans; } static void freebytes(Bytes* b) { if(b != nil) free(b); } /* * Make a new Bytes, containing bytes of b1 followed by those of b2. * Either b1 or b2 or both can be nil. */ static Bytes* catbytes(Bytes* b1, Bytes* b2) { Bytes* ans; int n; if(b1 == nil) { if(b2 == nil) ans = newbytes(0); else ans = makebytes(b2->data, b2->len); } else if(b2 == nil) { ans = makebytes(b1->data, b1->len); } else { n = b1->len + b2->len; ans = newbytes(n); ans->len = n; memmove(ans->data, b1->data, b1->len); memmove(ans->data+b1->len, b2->data, b2->len); } return ans; } /* len is number of ints */ static Ints* newints(int len) { Ints* ans; ans = (Ints*)emalloc(OFFSETOF(data[0], Ints) + len*sizeof(int)); ans->len = len; return ans; } static Ints* makeints(int* buf, int len) { Ints* ans; ans = newints(len); if(len > 0) memmove(ans->data, buf, len*sizeof(int)); return ans; } static void freeints(Ints* b) { if(b != nil) free(b); } /* len is number of bytes */ static Bits* newbits(int len) { Bits* ans; ans = (Bits*)emalloc(OFFSETOF(data[0], Bits) + len); ans->len = len; ans->unusedbits = 0; return ans; } static Bits* makebits(uchar* buf, int len, int unusedbits) { Bits* ans; ans = newbits(len); memmove(ans->data, buf, len); ans->unusedbits = unusedbits; return ans; } static void freebits(Bits* b) { if(b != nil) free(b); } static Elist* mkel(Elem e, Elist* tail) { Elist* el; el = (Elist*)emalloc(sizeof(Elist)); el->hd = e; el->tl = tail; return el; } static int elistlen(Elist* el) { int ans = 0; while(el != nil) { ans++; el = el->tl; } return ans; } /* Frees elist, but not fields inside values of constituent elems */ static void freeelist(Elist* el) { Elist* next; while(el != nil) { next = el->tl; free(el); el = next; } } /* free any allocated structures inside v (recursively freeing Elists) */ static void freevalfields(Value* v) { Elist* el; Elist* l; if(v == nil) return; switch(v->tag) { case VOctets: freebytes(v->u.octetsval); break; case VBigInt: freebytes(v->u.bigintval); break; case VReal: freebytes(v->u.realval); break; case VOther: freebytes(v->u.otherval); break; case VBitString: freebits(v->u.bitstringval); break; case VObjId: freeints(v->u.objidval); break; case VString: if (v->u.stringval) free(v->u.stringval); break; case VSeq: el = v->u.seqval; for(l = el; l != nil; l = l->tl) freevalfields(&l->hd.val); if (el) freeelist(el); break; case VSet: el = v->u.setval; for(l = el; l != nil; l = l->tl) freevalfields(&l->hd.val); if (el) freeelist(el); break; } } /* end of general ASN1 functions */ /*=============================================================*/ /* * Decode and parse an X.509 Certificate, defined by this ASN1: * Certificate ::= SEQUENCE { * certificateInfo CertificateInfo, * signatureAlgorithm AlgorithmIdentifier, * signature BIT STRING } * * CertificateInfo ::= SEQUENCE { * version [0] INTEGER DEFAULT v1 (0), * serialNumber INTEGER, * signature AlgorithmIdentifier, * issuer Name, * validity Validity, * subject Name, * subjectPublicKeyInfo SubjectPublicKeyInfo } * (version v2 has two more fields, optional unique identifiers for * issuer and subject; since we ignore these anyway, we won't parse them) * * Validity ::= SEQUENCE { * notBefore UTCTime, * notAfter UTCTime } * * SubjectPublicKeyInfo ::= SEQUENCE { * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING } * * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFER, * parameters ANY DEFINED BY ALGORITHM OPTIONAL } * * Name ::= SEQUENCE OF RelativeDistinguishedName * * RelativeDistinguishedName ::= SETOF SIZE(1..MAX) OF AttributeTypeAndValue * * AttributeTypeAndValue ::= SEQUENCE { * type OBJECT IDENTIFER, * value DirectoryString } * (selected attributes have these Object Ids: * commonName {2 5 4 3} * countryName {2 5 4 6} * localityName {2 5 4 7} * stateOrProvinceName {2 5 4 8} * organizationName {2 5 4 10} * organizationalUnitName {2 5 4 11} * ) * * DirectoryString ::= CHOICE { * teletexString TeletexString, * printableString PrintableString, * universalString UniversalString } * * See rfc1423, rfc2437 for AlgorithmIdentifier, subjectPublicKeyInfo, signature. * * Not yet implemented: * CertificateRevocationList ::= SIGNED SEQUENCE{ * signature AlgorithmIdentifier, * issuer Name, * lastUpdate UTCTime, * nextUpdate UTCTime, * revokedCertificates * SEQUENCE OF CRLEntry OPTIONAL} * CRLEntry ::= SEQUENCE{ * userCertificate SerialNumber, * revocationDate UTCTime} */ typedef struct CertX509 { int serial; char* issuer; char* validity_start; char* validity_end; char* subject; int publickey_alg; Bytes* publickey; int signature_alg; Bytes* signature; } CertX509; /* Algorithm object-ids */ enum { ALG_rsaEncryption, ALG_md2WithRSAEncryption, ALG_md4WithRSAEncryption, ALG_md5WithRSAEncryption, ALG_sha1WithRSAEncryption, ALG_md5, NUMALGS }; typedef struct Ints7 { int len; int data[7]; } Ints7; static Ints7 oid_rsaEncryption = {7, 1, 2, 840, 113549, 1, 1, 1 }; static Ints7 oid_md2WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 2 }; static Ints7 oid_md4WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 3 }; static Ints7 oid_md5WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 4 }; static Ints7 oid_sha1WithRSAEncryption ={7, 1, 2, 840, 113549, 1, 1, 5 }; static Ints7 oid_md5 ={6, 1, 2, 840, 113549, 2, 5, 0 }; static Ints *alg_oid_tab[NUMALGS+1] = { (Ints*)&oid_rsaEncryption, (Ints*)&oid_md2WithRSAEncryption, (Ints*)&oid_md4WithRSAEncryption, (Ints*)&oid_md5WithRSAEncryption, (Ints*)&oid_sha1WithRSAEncryption, (Ints*)&oid_md5, nil }; static DigestFun digestalg[NUMALGS+1] = { md5, md5, md5, md5, sha1, md5, nil }; static void freecert(CertX509* c) { if (!c) return; if(c->issuer != nil) free(c->issuer); if(c->validity_start != nil) free(c->validity_start); if(c->validity_end != nil) free(c->validity_end); if(c->subject != nil) free(c->subject); freebytes(c->publickey); freebytes(c->signature); } /* * Parse the Name ASN1 type. * The sequence of RelativeDistinguishedName's gives a sort of pathname, * from most general to most specific. Each element of the path can be * one or more (but usually just one) attribute-value pair, such as * countryName="US". * We'll just form a "postal-style" address string by concatenating the elements * from most specific to least specific, separated by commas. * Return name-as-string (which must be freed by caller). */ static char* parse_name(Elem* e) { Elist* el; Elem* es; Elist* esetl; Elem* eat; Elist* eatl; char* s; enum { MAXPARTS = 100 }; char* parts[MAXPARTS]; int i; int plen; char* ans = nil; if(!is_seq(e, &el)) goto errret; i = 0; plen = 0; while(el != nil) { es = &el->hd; if(!is_set(es, &esetl)) goto errret; while(esetl != nil) { eat = &esetl->hd; if(!is_seq(eat, &eatl) || elistlen(eatl) != 2) goto errret; if(!is_string(&eatl->tl->hd, &s) || i>=MAXPARTS) goto errret; parts[i++] = s; plen += strlen(s) + 2; /* room for ", " after */ esetl = esetl->tl; } el = el->tl; } if(i > 0) { ans = (char*)emalloc(plen); *ans = '\0'; while(--i >= 0) { s = parts[i]; strcat(ans, s); if(i > 0) strcat(ans, ", "); } } errret: return ans; } /* * Parse an AlgorithmIdentifer ASN1 type. * Look up the oid in oid_tab and return one of OID_rsaEncryption, etc.., * or -1 if not found. * For now, ignore parameters, since none of our algorithms need them. */ static int parse_alg(Elem* e) { Elist* el; Ints* oid; if(!is_seq(e, &el) || el == nil || !is_oid(&el->hd, &oid)) return -1; return oid_lookup(oid, alg_oid_tab); } static CertX509* decode_cert(Bytes* a) { int ok = 0; int n; CertX509* c = nil; Elem ecert; Elem* ecertinfo; Elem* esigalg; Elem* esig; Elem* eserial; Elem* eissuer; Elem* evalidity; Elem* esubj; Elem* epubkey; Elist* el; Elist* elcert = nil; Elist* elcertinfo = nil; Elist* elvalidity = nil; Elist* elpubkey = nil; Bits* bits = nil; Bytes* b; Elem* e; if(decode(a->data, a->len, &ecert) != ASN_OK) goto errret; c = (CertX509*)emalloc(sizeof(CertX509)); c->serial = -1; c->issuer = nil; c->validity_start = nil; c->validity_end = nil; c->subject = nil; c->publickey_alg = -1; c->publickey = nil; c->signature_alg = -1; c->signature = nil; /* Certificate */ if(!is_seq(&ecert, &elcert) || elistlen(elcert) !=3) goto errret; ecertinfo = &elcert->hd; el = elcert->tl; esigalg = &el->hd; c->signature_alg = parse_alg(esigalg); el = el->tl; esig = &el->hd; /* Certificate Info */ if(!is_seq(ecertinfo, &elcertinfo)) goto errret; n = elistlen(elcertinfo); if(n < 6) goto errret; eserial =&elcertinfo->hd; el = elcertinfo->tl; /* check for optional version, marked by explicit context tag 0 */ if(eserial->tag.class == Context && eserial->tag.num == 0) { eserial = &el->hd; if(n < 7) goto errret; el = el->tl; } if(parse_alg(&el->hd) != c->signature_alg) goto errret; el = el->tl; eissuer = &el->hd; el = el->tl; evalidity = &el->hd; el = el->tl; esubj = &el->hd; el = el->tl; epubkey = &el->hd; if(!is_int(eserial, &c->serial)) { if(!is_bigint(eserial, &b)) goto errret; c->serial = -1; /* else we have to change cert struct */ } c->issuer = parse_name(eissuer); if(c->issuer == nil) goto errret; /* Validity */ if(!is_seq(evalidity, &elvalidity)) goto errret; if(elistlen(elvalidity) != 2) goto errret; e = &elvalidity->hd; if(!is_time(e, &c->validity_start)) goto errret; e->val.u.stringval = nil; /* string ownership transfer */ e = &elvalidity->tl->hd; if(!is_time(e, &c->validity_end)) goto errret; e->val.u.stringval = nil; /* string ownership transfer */ /* resume CertificateInfo */ c->subject = parse_name(esubj); if(c->subject == nil) goto errret; /* SubjectPublicKeyInfo */ if(!is_seq(epubkey, &elpubkey)) goto errret; if(elistlen(elpubkey) != 2) goto errret; c->publickey_alg = parse_alg(&elpubkey->hd); if(c->publickey_alg < 0) goto errret; if(!is_bitstring(&elpubkey->tl->hd, &bits)) goto errret; if(bits->unusedbits != 0) goto errret; c->publickey = makebytes(bits->data, bits->len); /*resume Certificate */ if(c->signature_alg < 0) goto errret; if(!is_bitstring(esig, &bits)) goto errret; c->signature = makebytes(bits->data, bits->len); ok = 1; errret: freevalfields(&ecert.val); /* recurses through lists, too */ if(!ok){ freecert(c); c = nil; } return c; } /* * RSAPublickKey :: SEQUENCE { * modulus INTEGER, * publicExponent INTEGER * } */ static RSApub* decode_rsapubkey(Bytes* a) { Elem e; Elist *el; mpint *mp; RSApub* key; key = rsapuballoc(); if(decode(a->data, a->len, &e) != ASN_OK) goto errret; if(!is_seq(&e, &el) || elistlen(el) != 2) goto errret; key->n = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; el = el->tl; key->ek = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; return key; errret: rsapubfree(key); return nil; } /* * RSAPrivateKey ::= SEQUENCE { * version Version, * modulus INTEGER, -- n * publicExponent INTEGER, -- e * privateExponent INTEGER, -- d * prime1 INTEGER, -- p * prime2 INTEGER, -- q * exponent1 INTEGER, -- d mod (p-1) * exponent2 INTEGER, -- d mod (q-1) * coefficient INTEGER -- (inverse of q) mod p } */ static RSApriv* decode_rsaprivkey(Bytes* a) { int version; Elem e; Elist *el; mpint *mp; RSApriv* key; key = rsaprivalloc(); if(decode(a->data, a->len, &e) != ASN_OK) goto errret; if(!is_seq(&e, &el) || elistlen(el) != 9) goto errret; if(!is_int(&el->hd, &version) || version != 0) goto errret; el = el->tl; key->pub.n = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; el = el->tl; key->pub.ek = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; el = el->tl; key->dk = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; el = el->tl; key->q = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; el = el->tl; key->p = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; el = el->tl; key->kq = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; el = el->tl; key->kp = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; el = el->tl; key->c2 = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; return key; errret: rsaprivfree(key); return nil; } static mpint* asn1mpint(Elem *e) { Bytes *b; mpint *mp; int v; if(is_int(e, &v)) return itomp(v, nil); if(is_bigint(e, &b)) { mp = betomp(b->data, b->len, nil); freebytes(b); return mp; } return nil; } static mpint* pkcs1pad(Bytes *b, mpint *modulus) { int n = (mpsignif(modulus)+7)/8; int pm1, i; uchar *p; mpint *mp; pm1 = n - 1 - b->len; p = (uchar*)emalloc(n); p[0] = 0; p[1] = 1; for(i = 2; i < pm1; i++) p[i] = 0xFF; p[pm1] = 0; memcpy(&p[pm1+1], b->data, b->len); mp = betomp(p, n, nil); free(p); return mp; } RSApriv* asn1toRSApriv(uchar *kd, int kn) { Bytes *b; RSApriv *key; b = makebytes(kd, kn); key = decode_rsaprivkey(b); freebytes(b); return key; } /* * digest(CertificateInfo) * Our ASN.1 library doesn't return pointers into the original * data array, so we need to do a little hand decoding. */ static void digest_certinfo(Bytes *cert, DigestFun digestfun, uchar *digest) { uchar *info, *p, *pend; ulong infolen; int isconstr, length; Tag tag; Elem elem; p = cert->data; pend = cert->data + cert->len; if(tag_decode(&p, pend, &tag, &isconstr) != ASN_OK || tag.class != Universal || tag.num != SEQUENCE || length_decode(&p, pend, &length) != ASN_OK || p+length > pend) return; info = p; if(ber_decode(&p, pend, &elem) != ASN_OK || elem.tag.num != SEQUENCE) return; infolen = p - info; (*digestfun)(info, infolen, digest, nil); } static char* verify_signature(Bytes* signature, RSApub *pk, uchar *edigest, Elem **psigalg) { Elem e; Elist *el; Bytes *digest; uchar *pkcs1buf, *buf; int buflen; mpint *pkcs1; /* see 9.2.1 of rfc2437 */ pkcs1 = betomp(signature->data, signature->len, nil); mpexp(pkcs1, pk->ek, pk->n, pkcs1); buflen = mptobe(pkcs1, nil, 0, &pkcs1buf); buf = pkcs1buf; if(buflen < 4 || buf[0] != 1) return "expected 1"; buf++; while(buf[0] == 0xff) buf++; if(buf[0] != 0) return "expected 0"; buf++; buflen -= buf-pkcs1buf; if(decode(buf, buflen, &e) != ASN_OK || !is_seq(&e, &el) || elistlen(el) != 2 || !is_octetstring(&el->tl->hd, &digest)) return "signature parse error"; *psigalg = &el->hd; if(memcmp(digest->data, edigest, digest->len) == 0) return nil; return "digests did not match"; } RSApub* X509toRSApub(uchar *cert, int ncert, char *name, int nname) { char *e; Bytes *b; CertX509 *c; RSApub *pk; b = makebytes(cert, ncert); c = decode_cert(b); freebytes(b); if(c == nil) return nil; if(name != nil && c->subject != nil){ e = strchr(c->subject, ','); if(e != nil) *e = 0; // take just CN part of Distinguished Name strncpy(name, c->subject, nname); } pk = decode_rsapubkey(c->publickey); freecert(c); return pk; } char* X509verify(uchar *cert, int ncert, RSApub *pk) { char *e; Bytes *b; CertX509 *c; uchar digest[SHA1dlen]; Elem *sigalg; b = makebytes(cert, ncert); c = decode_cert(b); if(c != nil) digest_certinfo(b, digestalg[c->signature_alg], digest); freebytes(b); if(c == nil) return "cannot decode cert"; e = verify_signature(c->signature, pk, digest, &sigalg); freecert(c); return e; } /* ------- Elem constructors ---------- */ static Elem Null(void) { Elem e; e.tag.class = Universal; e.tag.num = NULLTAG; e.val.tag = VNull; return e; } static Elem mkint(int j) { Elem e; e.tag.class = Universal; e.tag.num = INTEGER; e.val.tag = VInt; e.val.u.intval = j; return e; } static Elem mkbigint(mpint *p) { Elem e; uchar *buf; int buflen; e.tag.class = Universal; e.tag.num = INTEGER; e.val.tag = VBigInt; buflen = mptobe(p, nil, 0, &buf); e.val.u.bigintval = makebytes(buf, buflen); free(buf); return e; } static Elem mkstring(char *s) { Elem e; e.tag.class = Universal; e.tag.num = IA5String; e.val.tag = VString; e.val.u.stringval = estrdup(s); return e; } static Elem mkoctet(uchar *buf, int buflen) { Elem e; e.tag.class = Universal; e.tag.num = OCTET_STRING; e.val.tag = VOctets; e.val.u.octetsval = makebytes(buf, buflen); return e; } static Elem mkbits(uchar *buf, int buflen) { Elem e; e.tag.class = Universal; e.tag.num = BIT_STRING; e.val.tag = VBitString; e.val.u.bitstringval = makebits(buf, buflen, 0); return e; } static Elem mkutc(long t) { Elem e; char utc[50]; Tm *tm = gmtime(t); e.tag.class = Universal; e.tag.num = UTCTime; e.val.tag = VString; snprint(utc, 50, "%.2d%.2d%.2d%.2d%.2d%.2dZ", tm->year % 100, tm->mon+1, tm->mday, tm->hour, tm->min, tm->sec); e.val.u.stringval = estrdup(utc); return e; } static Elem mkoid(Ints *oid) { Elem e; e.tag.class = Universal; e.tag.num = OBJECT_ID; e.val.tag = VObjId; e.val.u.objidval = makeints(oid->data, oid->len); return e; } static Elem mkseq(Elist *el) { Elem e; e.tag.class = Universal; e.tag.num = SEQUENCE; e.val.tag = VSeq; e.val.u.seqval = el; return e; } static Elem mkset(Elist *el) { Elem e; e.tag.class = Universal; e.tag.num = SETOF; e.val.tag = VSet; e.val.u.setval = el; return e; } static Elem mkalg(int alg) { return mkseq(mkel(mkoid(alg_oid_tab[alg]), mkel(Null(), nil))); } typedef struct Ints7pref { int len; int data[7]; char prefix[4]; } Ints7pref; Ints7pref DN_oid[] = { {4, 2, 5, 4, 6, 0, 0, 0, "C="}, {4, 2, 5, 4, 8, 0, 0, 0, "ST="}, {4, 2, 5, 4, 7, 0, 0, 0, "L="}, {4, 2, 5, 4, 10, 0, 0, 0, "O="}, {4, 2, 5, 4, 11, 0, 0, 0, "OU="}, {4, 2, 5, 4, 3, 0, 0, 0, "CN="}, {7, 1,2,840,113549,1,9,1, "E="}, }; static Elem mkname(Ints7pref *oid, char *subj) { return mkset(mkel(mkseq(mkel(mkoid((Ints*)oid), mkel(mkstring(subj), nil))), nil)); } static Elem mkDN(char *dn) { int i, j, nf; char *f[20], *prefix, *d2 = estrdup(dn); Elist* el = nil; nf = tokenize(d2, f, nelem(f)); for(i=nf-1; i>=0; i--){ for(j=0; jn),mkel(mkint(mptoi(pk->ek)),nil))); if(encode(pubkey, &pkbytes) != ASN_OK) goto errret; freevalfields(&pubkey.val); pubkey = mkseq( mkel(mkalg(ALG_rsaEncryption), mkel(mkbits(pkbytes->data, pkbytes->len), nil))); freebytes(pkbytes); validity = mkseq( mkel(mkutc(valid[0]), mkel(mkutc(valid[1]), nil))); certinfo = mkseq( mkel(mkint(serial), mkel(mkalg(ALG_md5WithRSAEncryption), mkel(issuer, mkel(validity, mkel(subject, mkel(pubkey, nil))))))); if(encode(certinfo, &certinfobytes) != ASN_OK) goto errret; md5(certinfobytes->data, certinfobytes->len, digest, 0); freebytes(certinfobytes); sig = mkseq( mkel(mkalg(ALG_md5), mkel(mkoctet(digest, MD5dlen), nil))); if(encode(sig, &sigbytes) != ASN_OK) goto errret; pkcs1 = pkcs1pad(sigbytes, pk->n); freebytes(sigbytes); rsadecrypt(priv, pkcs1, pkcs1); buflen = mptobe(pkcs1, nil, 0, &buf); mpfree(pkcs1); e = mkseq( mkel(certinfo, mkel(mkalg(ALG_md5WithRSAEncryption), mkel(mkbits(buf, buflen), nil)))); free(buf); if(encode(e, &certbytes) != ASN_OK) goto errret; if(certlen) *certlen = certbytes->len; cert = certbytes->data; errret: freevalfields(&e.val); return cert; } uchar* X509req(RSApriv *priv, char *subj, int *certlen) { /* RFC 2314, PKCS #10 Certification Request Syntax */ int version = 0; uchar *cert = nil; RSApub *pk = rsaprivtopub(priv); Bytes *certbytes, *pkbytes, *certinfobytes, *sigbytes; Elem e, certinfo, subject, pubkey, sig; uchar digest[MD5dlen], *buf; int buflen; mpint *pkcs1; e.val.tag = VInt; /* so freevalfields at errret is no-op */ subject = mkDN(subj); pubkey = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil))); if(encode(pubkey, &pkbytes) != ASN_OK) goto errret; freevalfields(&pubkey.val); pubkey = mkseq( mkel(mkalg(ALG_rsaEncryption), mkel(mkbits(pkbytes->data, pkbytes->len), nil))); freebytes(pkbytes); certinfo = mkseq( mkel(mkint(version), mkel(subject, mkel(pubkey, nil)))); if(encode(certinfo, &certinfobytes) != ASN_OK) goto errret; md5(certinfobytes->data, certinfobytes->len, digest, 0); freebytes(certinfobytes); sig = mkseq( mkel(mkalg(ALG_md5), mkel(mkoctet(digest, MD5dlen), nil))); if(encode(sig, &sigbytes) != ASN_OK) goto errret; pkcs1 = pkcs1pad(sigbytes, pk->n); freebytes(sigbytes); rsadecrypt(priv, pkcs1, pkcs1); buflen = mptobe(pkcs1, nil, 0, &buf); mpfree(pkcs1); e = mkseq( mkel(certinfo, mkel(mkalg(ALG_md5), mkel(mkbits(buf, buflen), nil)))); free(buf); if(encode(e, &certbytes) != ASN_OK) goto errret; if(certlen) *certlen = certbytes->len; cert = certbytes->data; errret: freevalfields(&e.val); return cert; } static char* tagdump(Tag tag) { if(tag.class != Universal) return smprint("class%d,num%d", tag.class, tag.num); switch(tag.num){ case BOOLEAN: return "BOOLEAN"; break; case INTEGER: return "INTEGER"; break; case BIT_STRING: return "BIT STRING"; break; case OCTET_STRING: return "OCTET STRING"; break; case NULLTAG: return "NULLTAG"; break; case OBJECT_ID: return "OID"; break; case ObjectDescriptor: return "OBJECT_DES"; break; case EXTERNAL: return "EXTERNAL"; break; case REAL: return "REAL"; break; case ENUMERATED: return "ENUMERATED"; break; case EMBEDDED_PDV: return "EMBEDDED PDV"; break; case SEQUENCE: return "SEQUENCE"; break; case SETOF: return "SETOF"; break; case NumericString: return "NumericString"; break; case PrintableString: return "PrintableString"; break; case TeletexString: return "TeletexString"; break; case VideotexString: return "VideotexString"; break; case IA5String: return "IA5String"; break; case UTCTime: return "UTCTime"; break; case GeneralizedTime: return "GeneralizedTime"; break; case GraphicString: return "GraphicString"; break; case VisibleString: return "VisibleString"; break; case GeneralString: return "GeneralString"; break; case UniversalString: return "UniversalString"; break; case BMPString: return "BMPString"; break; default: return smprint("Universal,num%d", tag.num); } } static void edump(Elem e) { Value v; Elist *el; int i; print("%s{", tagdump(e.tag)); v = e.val; switch(v.tag){ case VBool: print("Bool %d",v.u.boolval); break; case VInt: print("Int %d",v.u.intval); break; case VOctets: print("Octets[%d] %.2x%.2x...",v.u.octetsval->len,v.u.octetsval->data[0],v.u.octetsval->data[1]); break; case VBigInt: print("BigInt[%d] %.2x%.2x...",v.u.bigintval->len,v.u.bigintval->data[0],v.u.bigintval->data[1]); break; case VReal: print("Real..."); break; case VOther: print("Other..."); break; case VBitString: print("BitString..."); break; case VNull: print("Null"); break; case VEOC: print("EOC..."); break; case VObjId: print("ObjId"); for(i = 0; ilen; i++) print(" %d", v.u.objidval->data[i]); break; case VString: print("String \"%s\"",v.u.stringval); break; case VSeq: print("Seq\n"); for(el = v.u.seqval; el!=nil; el = el->tl) edump(el->hd); break; case VSet: print("Set\n"); for(el = v.u.setval; el!=nil; el = el->tl) edump(el->hd); break; } print("}\n"); } void asn1dump(uchar *der, int len) { Elem e; if(decode(der, len, &e) != ASN_OK){ print("didn't parse\n"); exits("didn't parse"); } edump(e); } void X509dump(uchar *cert, int ncert) { char *e; Bytes *b; CertX509 *c; RSApub *pk; uchar digest[SHA1dlen]; Elem *sigalg; print("begin X509dump\n"); b = makebytes(cert, ncert); c = decode_cert(b); if(c != nil) digest_certinfo(b, digestalg[c->signature_alg], digest); freebytes(b); if(c == nil){ print("cannot decode cert"); return; } print("serial %d\n", c->serial); print("issuer %s\n", c->issuer); print("validity %s %s\n", c->validity_start, c->validity_end); print("subject %s\n", c->subject); pk = decode_rsapubkey(c->publickey); print("pubkey e=%B n(%d)=%B\n", pk->ek, mpsignif(pk->n), pk->n); print("sigalg=%d digest=%.*H\n", c->signature_alg, MD5dlen, digest); e = verify_signature(c->signature, pk, digest, &sigalg); if(e==nil){ e = "nil (meaning ok)"; print("sigalg=\n"); if(sigalg) edump(*sigalg); } print("self-signed verify_signature returns: %s\n", e); rsapubfree(pk); freecert(c); print("end X509dump\n"); } drawterm-20170818/main.c000066400000000000000000000046131314554504700147170ustar00rootroot00000000000000#include "u.h" #include "lib.h" #include "kern/dat.h" #include "kern/fns.h" #include "user.h" #include "drawterm.h" char *argv0; char *user; extern int errfmt(Fmt*); void sizebug(void) { /* * Needed by various parts of the code. * This is a huge bug. */ assert(sizeof(char)==1); assert(sizeof(short)==2); assert(sizeof(ushort)==2); assert(sizeof(int)==4); assert(sizeof(uint)==4); assert(sizeof(long)==4); assert(sizeof(ulong)==4); assert(sizeof(vlong)==8); assert(sizeof(uvlong)==8); } int main(int argc, char **argv) { eve = getuser(); if(eve == nil) eve = "drawterm"; sizebug(); osinit(); procinit0(); printinit(); screeninit(); chandevreset(); chandevinit(); quotefmtinstall(); if(bind("#c", "/dev", MBEFORE) < 0) panic("bind #c: %r"); if(bind("#m", "/dev", MBEFORE) < 0) panic("bind #m: %r"); if(bind("#i", "/dev", MBEFORE) < 0) panic("bind #i: %r"); if(bind("#I", "/net", MBEFORE) < 0) panic("bind #I: %r"); if(bind("#U", "/", MAFTER) < 0) panic("bind #U: %r"); bind("#A", "/dev", MAFTER); if(open("/dev/cons", OREAD) != 0) panic("open0: %r"); if(open("/dev/cons", OWRITE) != 1) panic("open1: %r"); if(open("/dev/cons", OWRITE) != 2) panic("open2: %r"); cpumain(argc, argv); return 0; } char* getkey(char *user, char *dom) { char buf[1024]; snprint(buf, sizeof buf, "%s@%s password", user, dom); return readcons(buf, nil, 1); } char* findkey(char **puser, char *dom) { char buf[1024], *f[50], *p, *ep, *nextp, *pass, *user; int nf, haveproto, havedom, i; for(p=secstorebuf; *p; p=nextp){ nextp = strchr(p, '\n'); if(nextp == nil){ ep = p+strlen(p); nextp = ""; }else{ ep = nextp++; } if(ep-p >= sizeof buf){ print("warning: skipping long line in secstore factotum file\n"); continue; } memmove(buf, p, ep-p); buf[ep-p] = 0; nf = tokenize(buf, f, nelem(f)); if(nf == 0 || strcmp(f[0], "key") != 0) continue; pass = nil; haveproto = havedom = 0; user = nil; for(i=1; imd5block.s sha1block.s: sha1block.spp gcc -E - < sha1block.spp >sha1block.s drawterm-20170818/posix-386/getcallerpc.c000066400000000000000000000001361314554504700177340ustar00rootroot00000000000000#include "u.h" #include "libc.h" uintptr getcallerpc(void *a) { return ((uintptr*)a)[-1]; } drawterm-20170818/posix-386/md5block.spp000066400000000000000000000145471314554504700175420ustar00rootroot00000000000000/* * rfc1321 requires that I include this. The code is new. The constants * all come from the rfc (hence the copyright). We trade a table for the * macros in rfc. The total size is a lot less. -- presotto * * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it * is identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided * that such works are identified as "derived from the RSA Data * Security, Inc. MD5 Message-Digest Algorithm" in all material * mentioning or referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software forany particular purpose. It is provided "as is" * without express or implied warranty of any kind. * These notices must be retained in any copies of any part of this * documentation and/or software. */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 #define PAYME(x) $##x /* * SI is data * a += FN(B,C,D); * a += x[sh] + t[sh]; * a = (a << S11) | (a >> (32 - S11)); * a += b; */ #define BODY1(off,V,FN,SH,A,B,C,D)\ FN(B,C,D)\ leal V(A, %edi, 1), A;\ addl off(%ebp), A;\ roll PAYME(SH), A;\ addl B, A;\ #define BODY(off,V,FN,SH,A,B,C,D)\ FN(B,C,D)\ leal V(A, %edi, 1), A;\ addl (off)(%ebp), A;\ roll PAYME(SH), A;\ addl B,A;\ /* * fn1 = ((c ^ d) & b) ^ d */ #define FN1(B,C,D)\ movl C, %edi;\ xorl D, %edi;\ andl B, %edi;\ xorl D, %edi;\ /* * fn2 = ((b ^ c) & d) ^ c; */ #define FN2(B,C,D)\ movl B, %edi;\ xorl C, %edi;\ andl D, %edi;\ xorl C, %edi;\ /* * fn3 = b ^ c ^ d; */ #define FN3(B,C,D)\ movl B, %edi;\ xorl C, %edi;\ xorl D, %edi;\ /* * fn4 = c ^ (b | ~d); */ #define FN4(B,C,D)\ movl D, %edi;\ xorl $-1, %edi;\ orl B, %edi;\ xorl C, %edi;\ #define STACKSIZE 20 #define DATA (STACKSIZE+8) #define LEN (STACKSIZE+12) #define STATE (STACKSIZE+16) #define EDATA (STACKSIZE-4) #define OLDEBX (STACKSIZE-8) #define OLDESI (STACKSIZE-12) #define OLDEDI (STACKSIZE-16) .text .p2align 2,0x90 #ifdef __APPLE__ .globl __md5block __md5block: #else .globl _md5block _md5block: #endif /* Prelude */ pushl %ebp subl $(STACKSIZE), %esp movl %ebx, OLDEBX(%esp) movl %esi, OLDESI(%esp) movl %edi, OLDEDI(%esp) movl DATA(%esp), %eax addl LEN(%esp), %eax movl %eax, EDATA(%esp) movl DATA(%esp), %ebp 0: movl STATE(%esp), %esi movl (%esi), %eax movl 4(%esi), %ebx movl 8(%esi), %ecx movl 12(%esi), %edx BODY1( 0*4,0xd76aa478,FN1,S11,%eax,%ebx,%ecx,%edx) BODY1( 1*4,0xe8c7b756,FN1,S12,%edx,%eax,%ebx,%ecx) BODY1( 2*4,0x242070db,FN1,S13,%ecx,%edx,%eax,%ebx) BODY1( 3*4,0xc1bdceee,FN1,S14,%ebx,%ecx,%edx,%eax) BODY1( 4*4,0xf57c0faf,FN1,S11,%eax,%ebx,%ecx,%edx) BODY1( 5*4,0x4787c62a,FN1,S12,%edx,%eax,%ebx,%ecx) BODY1( 6*4,0xa8304613,FN1,S13,%ecx,%edx,%eax,%ebx) BODY1( 7*4,0xfd469501,FN1,S14,%ebx,%ecx,%edx,%eax) BODY1( 8*4,0x698098d8,FN1,S11,%eax,%ebx,%ecx,%edx) BODY1( 9*4,0x8b44f7af,FN1,S12,%edx,%eax,%ebx,%ecx) BODY1(10*4,0xffff5bb1,FN1,S13,%ecx,%edx,%eax,%ebx) BODY1(11*4,0x895cd7be,FN1,S14,%ebx,%ecx,%edx,%eax) BODY1(12*4,0x6b901122,FN1,S11,%eax,%ebx,%ecx,%edx) BODY1(13*4,0xfd987193,FN1,S12,%edx,%eax,%ebx,%ecx) BODY1(14*4,0xa679438e,FN1,S13,%ecx,%edx,%eax,%ebx) BODY1(15*4,0x49b40821,FN1,S14,%ebx,%ecx,%edx,%eax) BODY( 1*4,0xf61e2562,FN2,S21,%eax,%ebx,%ecx,%edx) BODY( 6*4,0xc040b340,FN2,S22,%edx,%eax,%ebx,%ecx) BODY(11*4,0x265e5a51,FN2,S23,%ecx,%edx,%eax,%ebx) BODY( 0*4,0xe9b6c7aa,FN2,S24,%ebx,%ecx,%edx,%eax) BODY( 5*4,0xd62f105d,FN2,S21,%eax,%ebx,%ecx,%edx) BODY(10*4,0x02441453,FN2,S22,%edx,%eax,%ebx,%ecx) BODY(15*4,0xd8a1e681,FN2,S23,%ecx,%edx,%eax,%ebx) BODY( 4*4,0xe7d3fbc8,FN2,S24,%ebx,%ecx,%edx,%eax) BODY( 9*4,0x21e1cde6,FN2,S21,%eax,%ebx,%ecx,%edx) BODY(14*4,0xc33707d6,FN2,S22,%edx,%eax,%ebx,%ecx) BODY( 3*4,0xf4d50d87,FN2,S23,%ecx,%edx,%eax,%ebx) BODY( 8*4,0x455a14ed,FN2,S24,%ebx,%ecx,%edx,%eax) BODY(13*4,0xa9e3e905,FN2,S21,%eax,%ebx,%ecx,%edx) BODY( 2*4,0xfcefa3f8,FN2,S22,%edx,%eax,%ebx,%ecx) BODY( 7*4,0x676f02d9,FN2,S23,%ecx,%edx,%eax,%ebx) BODY(12*4,0x8d2a4c8a,FN2,S24,%ebx,%ecx,%edx,%eax) BODY( 5*4,0xfffa3942,FN3,S31,%eax,%ebx,%ecx,%edx) BODY( 8*4,0x8771f681,FN3,S32,%edx,%eax,%ebx,%ecx) BODY(11*4,0x6d9d6122,FN3,S33,%ecx,%edx,%eax,%ebx) BODY(14*4,0xfde5380c,FN3,S34,%ebx,%ecx,%edx,%eax) BODY( 1*4,0xa4beea44,FN3,S31,%eax,%ebx,%ecx,%edx) BODY( 4*4,0x4bdecfa9,FN3,S32,%edx,%eax,%ebx,%ecx) BODY( 7*4,0xf6bb4b60,FN3,S33,%ecx,%edx,%eax,%ebx) BODY(10*4,0xbebfbc70,FN3,S34,%ebx,%ecx,%edx,%eax) BODY(13*4,0x289b7ec6,FN3,S31,%eax,%ebx,%ecx,%edx) BODY( 0*4,0xeaa127fa,FN3,S32,%edx,%eax,%ebx,%ecx) BODY( 3*4,0xd4ef3085,FN3,S33,%ecx,%edx,%eax,%ebx) BODY( 6*4,0x04881d05,FN3,S34,%ebx,%ecx,%edx,%eax) BODY( 9*4,0xd9d4d039,FN3,S31,%eax,%ebx,%ecx,%edx) BODY(12*4,0xe6db99e5,FN3,S32,%edx,%eax,%ebx,%ecx) BODY(15*4,0x1fa27cf8,FN3,S33,%ecx,%edx,%eax,%ebx) BODY( 2*4,0xc4ac5665,FN3,S34,%ebx,%ecx,%edx,%eax) BODY( 0*4,0xf4292244,FN4,S41,%eax,%ebx,%ecx,%edx) BODY( 7*4,0x432aff97,FN4,S42,%edx,%eax,%ebx,%ecx) BODY(14*4,0xab9423a7,FN4,S43,%ecx,%edx,%eax,%ebx) BODY( 5*4,0xfc93a039,FN4,S44,%ebx,%ecx,%edx,%eax) BODY(12*4,0x655b59c3,FN4,S41,%eax,%ebx,%ecx,%edx) BODY( 3*4,0x8f0ccc92,FN4,S42,%edx,%eax,%ebx,%ecx) BODY(10*4,0xffeff47d,FN4,S43,%ecx,%edx,%eax,%ebx) BODY( 1*4,0x85845dd1,FN4,S44,%ebx,%ecx,%edx,%eax) BODY( 8*4,0x6fa87e4f,FN4,S41,%eax,%ebx,%ecx,%edx) BODY(15*4,0xfe2ce6e0,FN4,S42,%edx,%eax,%ebx,%ecx) BODY( 6*4,0xa3014314,FN4,S43,%ecx,%edx,%eax,%ebx) BODY(13*4,0x4e0811a1,FN4,S44,%ebx,%ecx,%edx,%eax) BODY( 4*4,0xf7537e82,FN4,S41,%eax,%ebx,%ecx,%edx) BODY(11*4,0xbd3af235,FN4,S42,%edx,%eax,%ebx,%ecx) BODY( 2*4,0x2ad7d2bb,FN4,S43,%ecx,%edx,%eax,%ebx) BODY( 9*4,0xeb86d391,FN4,S44,%ebx,%ecx,%edx,%eax) addl $(16*4), %ebp movl STATE(%esp), %edi addl %eax,0(%edi) addl %ebx,4(%edi) addl %ecx,8(%edi) addl %edx,12(%edi) movl EDATA(%esp), %edi cmpl %edi, %ebp jb 0b /* Postlude */ movl OLDEBX(%esp), %ebx movl OLDESI(%esp), %esi movl OLDEDI(%esp), %edi addl $(STACKSIZE), %esp popl %ebp ret drawterm-20170818/posix-386/sha1block.spp000066400000000000000000000112561314554504700177030ustar00rootroot00000000000000.text .p2align 2,0x90 #ifdef __APPLE__ .globl __sha1block __sha1block: #else .globl _sha1block _sha1block: #endif /* x = (wp[off-f] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1; * wp[off] = x; * x += A <<< 5; * E += 0xca62c1d6 + x; * x = FN(B,C,D); * E += x; * B >>> 2 */ #define BSWAPDI BYTE $0x0f; BYTE $0xcf; #define BODY(off,FN,V,A,B,C,D,E)\ movl (off-64)(%ebp), %edi;\ xorl (off-56)(%ebp), %edi;\ xorl (off-32)(%ebp), %edi;\ xorl (off-12)(%ebp), %edi;\ roll $1, %edi;\ movl %edi, off(%ebp);\ leal V(%edi, E, 1), E;\ movl A, %edi;\ roll $5, %edi;\ addl %edi, E;\ FN(B,C,D)\ addl %edi, E;\ rorl $2, B;\ #define BODY0(off,FN,V,A,B,C,D,E)\ movl off(%ebx), %edi;\ bswap %edi;\ movl %edi, off(%ebp);\ leal V(%edi,E,1), E;\ movl A, %edi;\ roll $5,%edi;\ addl %edi,E;\ FN(B,C,D)\ addl %edi,E;\ rorl $2,B;\ /* * fn1 = (((C^D)&B)^D); */ #define FN1(B,C,D)\ movl C, %edi;\ xorl D, %edi;\ andl B, %edi;\ xorl D, %edi;\ /* * fn24 = B ^ C ^ D */ #define FN24(B,C,D)\ movl B, %edi;\ xorl C, %edi;\ xorl D, %edi;\ /* * fn3 = ((B ^ C) & (D ^= B)) ^ B * D ^= B to restore D */ #define FN3(B,C,D)\ movl B, %edi;\ xorl C, %edi;\ xorl B, D;\ andl D, %edi;\ xorl B, %edi;\ xorl B, D;\ /* * stack offsets * void sha1block(uchar *DATA, int LEN, ulong *STATE) */ #define STACKSIZE (48+80*4) #define DATA (STACKSIZE+8) #define LEN (STACKSIZE+12) #define STATE (STACKSIZE+16) /* * stack offsets for locals * ulong w[80]; * uchar *edata; * ulong *w15, *w40, *w60, *w80; * register local * ulong *wp = %ebp * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi * ulong tmp = edi */ #define WARRAY (STACKSIZE-4-(80*4)) #define TMP1 (STACKSIZE-8-(80*4)) #define TMP2 (STACKSIZE-12-(80*4)) #define W15 (STACKSIZE-16-(80*4)) #define W40 (STACKSIZE-20-(80*4)) #define W60 (STACKSIZE-24-(80*4)) #define W80 (STACKSIZE-28-(80*4)) #define EDATA (STACKSIZE-32-(80*4)) #define OLDEBX (STACKSIZE-36-(80*4)) #define OLDESI (STACKSIZE-40-(80*4)) #define OLDEDI (STACKSIZE-44-(80*4)) /* Prelude */ pushl %ebp subl $(STACKSIZE), %esp mov %ebx, OLDEBX(%esp) mov %esi, OLDESI(%esp) mov %edi, OLDEDI(%esp) movl DATA(%esp), %eax addl LEN(%esp), %eax movl %eax, EDATA(%esp) leal (WARRAY+15*4)(%esp), %edi /* aw15 */ movl %edi, W15(%esp) leal (WARRAY+40*4)(%esp), %edx /* aw40 */ movl %edx, W40(%esp) leal (WARRAY+60*4)(%esp), %ecx /* aw60 */ movl %ecx, W60(%esp) leal (WARRAY+80*4)(%esp), %edi /* aw80 */ movl %edi, W80(%esp) 0: leal WARRAY(%esp), %ebp /* warray */ movl STATE(%esp), %edi /* state */ movl (%edi),%eax movl 4(%edi),%ebx movl %ebx, TMP1(%esp) /* tmp1 */ movl 8(%edi), %ecx movl 12(%edi), %edx movl 16(%edi), %esi movl DATA(%esp), %ebx /* data */ 1: BODY0(0,FN1,0x5a827999,%eax,TMP1(%esp),%ecx,%edx,%esi) movl %esi,TMP2(%esp) BODY0(4,FN1,0x5a827999,%esi,%eax,TMP1(%esp),%ecx,%edx) movl TMP1(%esp),%esi BODY0(8,FN1,0x5a827999,%edx,TMP2(%esp),%eax,%esi,%ecx) BODY0(12,FN1,0x5a827999,%ecx,%edx,TMP2(%esp),%eax,%esi) movl %esi,TMP1(%esp) BODY0(16,FN1,0x5a827999,%esi,%ecx,%edx,TMP2(%esp),%eax) movl TMP2(%esp),%esi addl $20, %ebx addl $20, %ebp cmpl W15(%esp), %ebp /* w15 */ jb 1b BODY0(0,FN1,0x5a827999,%eax,TMP1(%esp),%ecx,%edx,%esi) addl $4, %ebx MOVL %ebx, DATA(%esp) /* data */ MOVL TMP1(%esp),%ebx BODY(4,FN1,0x5a827999,%esi,%eax,%ebx,%ecx,%edx) BODY(8,FN1,0x5a827999,%edx,%esi,%eax,%ebx,%ecx) BODY(12,FN1,0x5a827999,%ecx,%edx,%esi,%eax,%ebx) BODY(16,FN1,0x5a827999,%ebx,%ecx,%edx,%esi,%eax) addl $20, %ebp 2: BODY(0,FN24,0x6ed9eba1,%eax,%ebx,%ecx,%edx,%esi) BODY(4,FN24,0x6ed9eba1,%esi,%eax,%ebx,%ecx,%edx) BODY(8,FN24,0x6ed9eba1,%edx,%esi,%eax,%ebx,%ecx) BODY(12,FN24,0x6ed9eba1,%ecx,%edx,%esi,%eax,%ebx) BODY(16,FN24,0x6ed9eba1,%ebx,%ecx,%edx,%esi,%eax) addl $20,%ebp cmpl W40(%esp), %ebp jb 2b 3: BODY(0,FN3,0x8f1bbcdc,%eax,%ebx,%ecx,%edx,%esi) BODY(4,FN3,0x8f1bbcdc,%esi,%eax,%ebx,%ecx,%edx) BODY(8,FN3,0x8f1bbcdc,%edx,%esi,%eax,%ebx,%ecx) BODY(12,FN3,0x8f1bbcdc,%ecx,%edx,%esi,%eax,%ebx) BODY(16,FN3,0x8f1bbcdc,%ebx,%ecx,%edx,%esi,%eax) addl $20, %ebp cmpl W60(%esp), %ebp /* w60 */ jb 3b 4: BODY(0,FN24,0xca62c1d6,%eax,%ebx,%ecx,%edx,%esi) BODY(4,FN24,0xca62c1d6,%esi,%eax,%ebx,%ecx,%edx) BODY(8,FN24,0xca62c1d6,%edx,%esi,%eax,%ebx,%ecx) BODY(12,FN24,0xca62c1d6,%ecx,%edx,%esi,%eax,%ebx) BODY(16,FN24,0xca62c1d6,%ebx,%ecx,%edx,%esi,%eax) addl $20, %ebp cmpl W80(%esp), %ebp /* w80 */ jb 4b movl STATE(%esp), %edi /* state */ addl %eax, 0(%edi) addl %ebx, 4(%edi) addl %ecx, 8(%edi) addl %edx, 12(%edi) addl %esi, 16(%edi) movl EDATA(%esp), %edi /* edata */ cmpl %edi, DATA(%esp) /* data */ jb 0b /* Postlude */ mov OLDEBX(%esp), %ebx mov OLDESI(%esp), %esi mov OLDEDI(%esp), %edi addl $(STACKSIZE), %esp popl %ebp ret drawterm-20170818/posix-386/tas.c000066400000000000000000000004161314554504700162370ustar00rootroot00000000000000#include "u.h" #include "libc.h" int tas(long *x) { int v; __asm__( "movl $1, %%eax\n\t" "xchgl %%eax,(%%ecx)" : "=a" (v) : "c" (x) ); switch(v) { case 0: case 1: return v; default: print("canlock: corrupted 0x%lux\n", v); return 1; } } drawterm-20170818/posix-amd64/000077500000000000000000000000001314554504700156765ustar00rootroot00000000000000drawterm-20170818/posix-amd64/Makefile000066400000000000000000000003431314554504700173360ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=../libmachdep.a OFILES=\ getcallerpc.$O\ md5block.$O\ sha1block.$O\ tas.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c drawterm-20170818/posix-amd64/getcallerpc.c000066400000000000000000000001361314554504700203270ustar00rootroot00000000000000#include "u.h" #include "libc.h" uintptr getcallerpc(void *a) { return ((uintptr*)a)[-1]; } drawterm-20170818/posix-amd64/md5block.c000066400000000000000000000116501314554504700175450ustar00rootroot00000000000000#include #include #include /* * rfc1321 requires that I include this. The code is new. The constants * all come from the rfc (hence the copyright). We trade a table for the * macros in rfc. The total size is a lot less. -- presotto * * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it * is identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided * that such works are identified as "derived from the RSA Data * Security, Inc. MD5 Message-Digest Algorithm" in all material * mentioning or referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software forany particular purpose. It is provided "as is" * without express or implied warranty of any kind. * These notices must be retained in any copies of any part of this * documentation and/or software. */ /* * Rotate ammounts used in the algorithm */ enum { S11= 7, S12= 12, S13= 17, S14= 22, S21= 5, S22= 9, S23= 14, S24= 20, S31= 4, S32= 11, S33= 16, S34= 23, S41= 6, S42= 10, S43= 15, S44= 21, }; static u32int md5tab[] = { /* round 1 */ /*[0]*/ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, /* round 2 */ /*[16]*/0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, /* round 3 */ /*[32]*/0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, /* round 4 */ /*[48]*/0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; static void decode(u32int*, uchar*, ulong); extern void _md5block(uchar *p, ulong len, u32int *s); void _md5block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, sh; u32int *t; uchar *end; u32int x[16]; for(end = p+len; p < end; p += 64){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; decode(x, p, 64); t = md5tab; sh = 0; for(; sh != 16; t += 4){ a += ((c ^ d) & b) ^ d; a += x[sh] + t[0]; a = (a << S11) | (a >> (32 - S11)); a += b; d += ((b ^ c) & a) ^ c; d += x[sh + 1] + t[1]; d = (d << S12) | (d >> (32 - S12)); d += a; c += ((a ^ b) & d) ^ b; c += x[sh + 2] + t[2]; c = (c << S13) | (c >> (32 - S13)); c += d; b += ((d ^ a) & c) ^ a; b += x[sh + 3] + t[3]; b = (b << S14) | (b >> (32 - S14)); b += c; sh += 4; } sh = 1; for(; sh != 1+20*4; t += 4){ a += ((b ^ c) & d) ^ c; a += x[sh & 0xf] + t[0]; a = (a << S21) | (a >> (32 - S21)); a += b; d += ((a ^ b) & c) ^ b; d += x[(sh + 5) & 0xf] + t[1]; d = (d << S22) | (d >> (32 - S22)); d += a; c += ((d ^ a) & b) ^ a; c += x[(sh + 10) & 0xf] + t[2]; c = (c << S23) | (c >> (32 - S23)); c += d; b += ((c ^ d) & a) ^ d; b += x[(sh + 15) & 0xf] + t[3]; b = (b << S24) | (b >> (32 - S24)); b += c; sh += 20; } sh = 5; for(; sh != 5+12*4; t += 4){ a += b ^ c ^ d; a += x[sh & 0xf] + t[0]; a = (a << S31) | (a >> (32 - S31)); a += b; d += a ^ b ^ c; d += x[(sh + 3) & 0xf] + t[1]; d = (d << S32) | (d >> (32 - S32)); d += a; c += d ^ a ^ b; c += x[(sh + 6) & 0xf] + t[2]; c = (c << S33) | (c >> (32 - S33)); c += d; b += c ^ d ^ a; b += x[(sh + 9) & 0xf] + t[3]; b = (b << S34) | (b >> (32 - S34)); b += c; sh += 12; } sh = 0; for(; sh != 28*4; t += 4){ a += c ^ (b | ~d); a += x[sh & 0xf] + t[0]; a = (a << S41) | (a >> (32 - S41)); a += b; d += b ^ (a | ~c); d += x[(sh + 7) & 0xf] + t[1]; d = (d << S42) | (d >> (32 - S42)); d += a; c += a ^ (d | ~b); c += x[(sh + 14) & 0xf] + t[2]; c = (c << S43) | (c >> (32 - S43)); c += d; b += d ^ (c | ~a); b += x[(sh + 21) & 0xf] + t[3]; b = (b << S44) | (b >> (32 - S44)); b += c; sh += 28; } s[0] += a; s[1] += b; s[2] += c; s[3] += d; } } /* * decodes input (uchar) into output (u32int). Assumes len is * a multiple of 4. */ static void decode(u32int *output, uchar *input, ulong len) { uchar *e; for(e = input+len; input < e; input += 4) *output++ = input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24); } drawterm-20170818/posix-amd64/sha1block.c000066400000000000000000000111461314554504700177140ustar00rootroot00000000000000#include #include #include void _sha1block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, e, x; uchar *end; u32int *wp, *wend; u32int w[80]; /* at this point, we have a multiple of 64 bytes */ for(end = p+len; p < end;){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; e = s[4]; wend = w + 15; for(wp = w; wp < wend; wp += 5){ wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); wp[1] = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7]; d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); wp[2] = (p[8]<<24) | (p[9]<<16) | (p[10]<<8) | p[11]; c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); wp[3] = (p[12]<<24) | (p[13]<<16) | (p[14]<<8) | p[15]; b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); wp[4] = (p[16]<<24) | (p[17]<<16) | (p[18]<<8) | p[19]; a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); p += 20; } wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); wp += 5; p += 4; wend = w + 40; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x6ed9eba1 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x6ed9eba1 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x6ed9eba1 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x6ed9eba1 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x6ed9eba1 + (c^d^e); c = (c<<30)|(c>>2); } wend = w + 60; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x8f1bbcdc + ((b&c)|((b|c)&d)); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x8f1bbcdc + ((a&b)|((a|b)&c)); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x8f1bbcdc + ((e&a)|((e|a)&b)); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x8f1bbcdc + ((d&e)|((d|e)&a)); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x8f1bbcdc + ((c&d)|((c|d)&e)); c = (c<<30)|(c>>2); } wend = w + 80; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0xca62c1d6 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0xca62c1d6 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0xca62c1d6 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0xca62c1d6 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0xca62c1d6 + (c^d^e); c = (c<<30)|(c>>2); } /* save state */ s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; } } drawterm-20170818/posix-amd64/tas.c000066400000000000000000000004211314554504700166260ustar00rootroot00000000000000#include "u.h" #include "libc.h" int tas(long *x) { int v; __asm__( "movl $1, %%eax\n\t" "xchgl %%eax,(%%rcx)" : "=a" (v) : "c" (x) ); switch(v) { case 0: case 1: return v; default: print("canlock: corrupted 0x%lux\n", v); return 1; } } drawterm-20170818/posix-arm/000077500000000000000000000000001314554504700155425ustar00rootroot00000000000000drawterm-20170818/posix-arm/Makefile000066400000000000000000000004431314554504700172030ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=../libmachdep.a OFILES=\ getcallerpc.$O\ md5block.$O\ sha1block.$O\ tas.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c %.$O: %.s $(AS) -o $*.$O $*.s %.s: %.spp cpp $*.spp >$*.s drawterm-20170818/posix-arm/getcallerpc.c000066400000000000000000000001361314554504700201730ustar00rootroot00000000000000#include "u.h" #include "libc.h" uintptr getcallerpc(void *a) { return ((uintptr*)a)[-1]; } drawterm-20170818/posix-arm/md5block.c000066400000000000000000000116501314554504700174110ustar00rootroot00000000000000#include #include #include /* * rfc1321 requires that I include this. The code is new. The constants * all come from the rfc (hence the copyright). We trade a table for the * macros in rfc. The total size is a lot less. -- presotto * * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it * is identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided * that such works are identified as "derived from the RSA Data * Security, Inc. MD5 Message-Digest Algorithm" in all material * mentioning or referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software forany particular purpose. It is provided "as is" * without express or implied warranty of any kind. * These notices must be retained in any copies of any part of this * documentation and/or software. */ /* * Rotate ammounts used in the algorithm */ enum { S11= 7, S12= 12, S13= 17, S14= 22, S21= 5, S22= 9, S23= 14, S24= 20, S31= 4, S32= 11, S33= 16, S34= 23, S41= 6, S42= 10, S43= 15, S44= 21, }; static u32int md5tab[] = { /* round 1 */ /*[0]*/ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, /* round 2 */ /*[16]*/0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, /* round 3 */ /*[32]*/0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, /* round 4 */ /*[48]*/0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; static void decode(u32int*, uchar*, ulong); extern void _md5block(uchar *p, ulong len, u32int *s); void _md5block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, sh; u32int *t; uchar *end; u32int x[16]; for(end = p+len; p < end; p += 64){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; decode(x, p, 64); t = md5tab; sh = 0; for(; sh != 16; t += 4){ a += ((c ^ d) & b) ^ d; a += x[sh] + t[0]; a = (a << S11) | (a >> (32 - S11)); a += b; d += ((b ^ c) & a) ^ c; d += x[sh + 1] + t[1]; d = (d << S12) | (d >> (32 - S12)); d += a; c += ((a ^ b) & d) ^ b; c += x[sh + 2] + t[2]; c = (c << S13) | (c >> (32 - S13)); c += d; b += ((d ^ a) & c) ^ a; b += x[sh + 3] + t[3]; b = (b << S14) | (b >> (32 - S14)); b += c; sh += 4; } sh = 1; for(; sh != 1+20*4; t += 4){ a += ((b ^ c) & d) ^ c; a += x[sh & 0xf] + t[0]; a = (a << S21) | (a >> (32 - S21)); a += b; d += ((a ^ b) & c) ^ b; d += x[(sh + 5) & 0xf] + t[1]; d = (d << S22) | (d >> (32 - S22)); d += a; c += ((d ^ a) & b) ^ a; c += x[(sh + 10) & 0xf] + t[2]; c = (c << S23) | (c >> (32 - S23)); c += d; b += ((c ^ d) & a) ^ d; b += x[(sh + 15) & 0xf] + t[3]; b = (b << S24) | (b >> (32 - S24)); b += c; sh += 20; } sh = 5; for(; sh != 5+12*4; t += 4){ a += b ^ c ^ d; a += x[sh & 0xf] + t[0]; a = (a << S31) | (a >> (32 - S31)); a += b; d += a ^ b ^ c; d += x[(sh + 3) & 0xf] + t[1]; d = (d << S32) | (d >> (32 - S32)); d += a; c += d ^ a ^ b; c += x[(sh + 6) & 0xf] + t[2]; c = (c << S33) | (c >> (32 - S33)); c += d; b += c ^ d ^ a; b += x[(sh + 9) & 0xf] + t[3]; b = (b << S34) | (b >> (32 - S34)); b += c; sh += 12; } sh = 0; for(; sh != 28*4; t += 4){ a += c ^ (b | ~d); a += x[sh & 0xf] + t[0]; a = (a << S41) | (a >> (32 - S41)); a += b; d += b ^ (a | ~c); d += x[(sh + 7) & 0xf] + t[1]; d = (d << S42) | (d >> (32 - S42)); d += a; c += a ^ (d | ~b); c += x[(sh + 14) & 0xf] + t[2]; c = (c << S43) | (c >> (32 - S43)); c += d; b += d ^ (c | ~a); b += x[(sh + 21) & 0xf] + t[3]; b = (b << S44) | (b >> (32 - S44)); b += c; sh += 28; } s[0] += a; s[1] += b; s[2] += c; s[3] += d; } } /* * decodes input (uchar) into output (u32int). Assumes len is * a multiple of 4. */ static void decode(u32int *output, uchar *input, ulong len) { uchar *e; for(e = input+len; input < e; input += 4) *output++ = input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24); } drawterm-20170818/posix-arm/sha1block.c000066400000000000000000000111461314554504700175600ustar00rootroot00000000000000#include #include #include void _sha1block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, e, x; uchar *end; u32int *wp, *wend; u32int w[80]; /* at this point, we have a multiple of 64 bytes */ for(end = p+len; p < end;){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; e = s[4]; wend = w + 15; for(wp = w; wp < wend; wp += 5){ wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); wp[1] = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7]; d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); wp[2] = (p[8]<<24) | (p[9]<<16) | (p[10]<<8) | p[11]; c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); wp[3] = (p[12]<<24) | (p[13]<<16) | (p[14]<<8) | p[15]; b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); wp[4] = (p[16]<<24) | (p[17]<<16) | (p[18]<<8) | p[19]; a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); p += 20; } wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); wp += 5; p += 4; wend = w + 40; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x6ed9eba1 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x6ed9eba1 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x6ed9eba1 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x6ed9eba1 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x6ed9eba1 + (c^d^e); c = (c<<30)|(c>>2); } wend = w + 60; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x8f1bbcdc + ((b&c)|((b|c)&d)); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x8f1bbcdc + ((a&b)|((a|b)&c)); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x8f1bbcdc + ((e&a)|((e|a)&b)); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x8f1bbcdc + ((d&e)|((d|e)&a)); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x8f1bbcdc + ((c&d)|((c|d)&e)); c = (c<<30)|(c>>2); } wend = w + 80; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0xca62c1d6 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0xca62c1d6 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0xca62c1d6 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0xca62c1d6 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0xca62c1d6 + (c^d^e); c = (c<<30)|(c>>2); } /* save state */ s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; } } drawterm-20170818/posix-arm/tas.c000066400000000000000000000006751314554504700165050ustar00rootroot00000000000000#include "u.h" #include "libc.h" int tas(long *x) { int v, t, i = 1; #if ARMv5 __asm__( "swp %0, %1, [%2]" : "=&r" (v) : "r" (1), "r" (x) : "memory" ); #else __asm__ ( "1: ldrex %0, [%2]\n" " strex %1, %3, [%2]\n" " teq %1, #0\n" " bne 1b" : "=&r" (v), "=&r" (t) : "r" (x), "r" (i) : "cc"); #endif switch(v) { case 0: case 1: return v; default: print("canlock: corrupted 0x%lux\n", v); return 1; } } drawterm-20170818/posix-factotum.c000066400000000000000000000035301314554504700167520ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include "drawterm.h" #undef socket #undef connect #undef getenv #undef access char* getuser(void) { static char user[64]; struct passwd *pw; pw = getpwuid(getuid()); if(pw == nil) return "none"; strecpy(user, user+sizeof user, pw->pw_name); return user; } /* * Absent other hints, it works reasonably well to use * the X11 display name as the name space identifier. * This is how sam's B has worked since the early days. * Since most programs using name spaces are also using X, * this still seems reasonable. Terminal-only sessions * can set $NAMESPACE. */ static char* nsfromdisplay(void) { char *disp, *p; if((disp = getenv("DISPLAY")) == nil){ werrstr("$DISPLAY not set"); return nil; } /* canonicalize: xxx:0.0 => xxx:0 */ p = strrchr(disp, ':'); if(p){ p++; while(isdigit((uchar)*p)) p++; if(strcmp(p, ".0") == 0) *p = 0; } return smprint("/tmp/ns.%s.%s", getuser(), disp); } char* getns(void) { char *ns; ns = getenv("NAMESPACE"); if(ns == nil) ns = nsfromdisplay(); if(ns == nil){ werrstr("$NAMESPACE not set, %r"); return nil; } return ns; } int dialfactotum(void) { int fd; struct sockaddr_un su; char *name; name = smprint("%s/factotum", getns()); if(name == nil || access(name, 0) < 0) return -1; memset(&su, 0, sizeof su); su.sun_family = AF_UNIX; if(strlen(name)+1 > sizeof su.sun_path){ werrstr("socket name too long"); return -1; } strcpy(su.sun_path, name); if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){ werrstr("socket: %r"); return -1; } if(connect(fd, (struct sockaddr*)&su, sizeof su) < 0){ werrstr("connect %s: %r", name); close(fd); return -1; } return lfdfd(fd); } drawterm-20170818/posix-mips/000077500000000000000000000000001314554504700157335ustar00rootroot00000000000000drawterm-20170818/posix-mips/Makefile000066400000000000000000000004561314554504700174000ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=../libmachdep.a OFILES=\ getcallerpc.$O\ md5block.$O\ sha1block.$O\ tas.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c %.$O: %.s $(AS) $(ASFLAGS) -o $*.$O $*.s %.s: %.spp cpp $*.spp >$*.s drawterm-20170818/posix-mips/getcallerpc.c000066400000000000000000000001321314554504700203600ustar00rootroot00000000000000#include "u.h" #include "libc.h" ulong getcallerpc(void *a) { return ((ulong*)a)[-1]; } drawterm-20170818/posix-mips/md5block.c000066400000000000000000000116501314554504700176020ustar00rootroot00000000000000#include #include #include /* * rfc1321 requires that I include this. The code is new. The constants * all come from the rfc (hence the copyright). We trade a table for the * macros in rfc. The total size is a lot less. -- presotto * * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it * is identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided * that such works are identified as "derived from the RSA Data * Security, Inc. MD5 Message-Digest Algorithm" in all material * mentioning or referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software forany particular purpose. It is provided "as is" * without express or implied warranty of any kind. * These notices must be retained in any copies of any part of this * documentation and/or software. */ /* * Rotate ammounts used in the algorithm */ enum { S11= 7, S12= 12, S13= 17, S14= 22, S21= 5, S22= 9, S23= 14, S24= 20, S31= 4, S32= 11, S33= 16, S34= 23, S41= 6, S42= 10, S43= 15, S44= 21, }; static u32int md5tab[] = { /* round 1 */ /*[0]*/ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, /* round 2 */ /*[16]*/0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, /* round 3 */ /*[32]*/0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, /* round 4 */ /*[48]*/0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; static void decode(u32int*, uchar*, ulong); extern void _md5block(uchar *p, ulong len, u32int *s); void _md5block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, sh; u32int *t; uchar *end; u32int x[16]; for(end = p+len; p < end; p += 64){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; decode(x, p, 64); t = md5tab; sh = 0; for(; sh != 16; t += 4){ a += ((c ^ d) & b) ^ d; a += x[sh] + t[0]; a = (a << S11) | (a >> (32 - S11)); a += b; d += ((b ^ c) & a) ^ c; d += x[sh + 1] + t[1]; d = (d << S12) | (d >> (32 - S12)); d += a; c += ((a ^ b) & d) ^ b; c += x[sh + 2] + t[2]; c = (c << S13) | (c >> (32 - S13)); c += d; b += ((d ^ a) & c) ^ a; b += x[sh + 3] + t[3]; b = (b << S14) | (b >> (32 - S14)); b += c; sh += 4; } sh = 1; for(; sh != 1+20*4; t += 4){ a += ((b ^ c) & d) ^ c; a += x[sh & 0xf] + t[0]; a = (a << S21) | (a >> (32 - S21)); a += b; d += ((a ^ b) & c) ^ b; d += x[(sh + 5) & 0xf] + t[1]; d = (d << S22) | (d >> (32 - S22)); d += a; c += ((d ^ a) & b) ^ a; c += x[(sh + 10) & 0xf] + t[2]; c = (c << S23) | (c >> (32 - S23)); c += d; b += ((c ^ d) & a) ^ d; b += x[(sh + 15) & 0xf] + t[3]; b = (b << S24) | (b >> (32 - S24)); b += c; sh += 20; } sh = 5; for(; sh != 5+12*4; t += 4){ a += b ^ c ^ d; a += x[sh & 0xf] + t[0]; a = (a << S31) | (a >> (32 - S31)); a += b; d += a ^ b ^ c; d += x[(sh + 3) & 0xf] + t[1]; d = (d << S32) | (d >> (32 - S32)); d += a; c += d ^ a ^ b; c += x[(sh + 6) & 0xf] + t[2]; c = (c << S33) | (c >> (32 - S33)); c += d; b += c ^ d ^ a; b += x[(sh + 9) & 0xf] + t[3]; b = (b << S34) | (b >> (32 - S34)); b += c; sh += 12; } sh = 0; for(; sh != 28*4; t += 4){ a += c ^ (b | ~d); a += x[sh & 0xf] + t[0]; a = (a << S41) | (a >> (32 - S41)); a += b; d += b ^ (a | ~c); d += x[(sh + 7) & 0xf] + t[1]; d = (d << S42) | (d >> (32 - S42)); d += a; c += a ^ (d | ~b); c += x[(sh + 14) & 0xf] + t[2]; c = (c << S43) | (c >> (32 - S43)); c += d; b += d ^ (c | ~a); b += x[(sh + 21) & 0xf] + t[3]; b = (b << S44) | (b >> (32 - S44)); b += c; sh += 28; } s[0] += a; s[1] += b; s[2] += c; s[3] += d; } } /* * decodes input (uchar) into output (u32int). Assumes len is * a multiple of 4. */ static void decode(u32int *output, uchar *input, ulong len) { uchar *e; for(e = input+len; input < e; input += 4) *output++ = input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24); } drawterm-20170818/posix-mips/sha1block.c000066400000000000000000000111461314554504700177510ustar00rootroot00000000000000#include #include #include void _sha1block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, e, x; uchar *end; u32int *wp, *wend; u32int w[80]; /* at this point, we have a multiple of 64 bytes */ for(end = p+len; p < end;){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; e = s[4]; wend = w + 15; for(wp = w; wp < wend; wp += 5){ wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); wp[1] = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7]; d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); wp[2] = (p[8]<<24) | (p[9]<<16) | (p[10]<<8) | p[11]; c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); wp[3] = (p[12]<<24) | (p[13]<<16) | (p[14]<<8) | p[15]; b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); wp[4] = (p[16]<<24) | (p[17]<<16) | (p[18]<<8) | p[19]; a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); p += 20; } wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); wp += 5; p += 4; wend = w + 40; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x6ed9eba1 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x6ed9eba1 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x6ed9eba1 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x6ed9eba1 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x6ed9eba1 + (c^d^e); c = (c<<30)|(c>>2); } wend = w + 60; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x8f1bbcdc + ((b&c)|((b|c)&d)); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x8f1bbcdc + ((a&b)|((a|b)&c)); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x8f1bbcdc + ((e&a)|((e|a)&b)); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x8f1bbcdc + ((d&e)|((d|e)&a)); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x8f1bbcdc + ((c&d)|((c|d)&e)); c = (c<<30)|(c>>2); } wend = w + 80; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0xca62c1d6 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0xca62c1d6 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0xca62c1d6 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0xca62c1d6 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0xca62c1d6 + (c^d^e); c = (c<<30)|(c>>2); } /* save state */ s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; } } drawterm-20170818/posix-mips/tas.s000066400000000000000000000005711314554504700167110ustar00rootroot00000000000000#include #include .globl tas .ent tas 2 tas: .set noreorder 1: ori t1, zero, 12345 /* t1 = 12345 */ ll t0, (a0) /* t0 = *a0 */ sc t1, (a0) /* *a0 = t1 if *a0 hasn't changed; t1=success */ beq t1, zero, 1b /* repeat if *a0 did change */ nop j $31 /* return */ or v0, t0, zero /* set return value on way out */ .set reorder .end tas drawterm-20170818/posix-port/000077500000000000000000000000001314554504700157475ustar00rootroot00000000000000drawterm-20170818/posix-port/Makefile000066400000000000000000000004331314554504700174070ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=../libmachdep.a OFILES=\ getcallerpc.$O\ md5block.$O\ sha1block.$O\ default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c %.$O: %.s $(AS) -o $*.$O $*.s %.s: %.spp cpp $*.spp >$*.s drawterm-20170818/posix-port/getcallerpc.c000066400000000000000000000001161314554504700203760ustar00rootroot00000000000000#include "u.h" #include "libc.h" uintptr getcallerpc(void *a) { return 0; } drawterm-20170818/posix-port/md5block.c000066400000000000000000000116501314554504700176160ustar00rootroot00000000000000#include #include #include /* * rfc1321 requires that I include this. The code is new. The constants * all come from the rfc (hence the copyright). We trade a table for the * macros in rfc. The total size is a lot less. -- presotto * * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it * is identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided * that such works are identified as "derived from the RSA Data * Security, Inc. MD5 Message-Digest Algorithm" in all material * mentioning or referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software forany particular purpose. It is provided "as is" * without express or implied warranty of any kind. * These notices must be retained in any copies of any part of this * documentation and/or software. */ /* * Rotate ammounts used in the algorithm */ enum { S11= 7, S12= 12, S13= 17, S14= 22, S21= 5, S22= 9, S23= 14, S24= 20, S31= 4, S32= 11, S33= 16, S34= 23, S41= 6, S42= 10, S43= 15, S44= 21, }; static u32int md5tab[] = { /* round 1 */ /*[0]*/ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, /* round 2 */ /*[16]*/0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, /* round 3 */ /*[32]*/0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, /* round 4 */ /*[48]*/0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; static void decode(u32int*, uchar*, ulong); extern void _md5block(uchar *p, ulong len, u32int *s); void _md5block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, sh; u32int *t; uchar *end; u32int x[16]; for(end = p+len; p < end; p += 64){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; decode(x, p, 64); t = md5tab; sh = 0; for(; sh != 16; t += 4){ a += ((c ^ d) & b) ^ d; a += x[sh] + t[0]; a = (a << S11) | (a >> (32 - S11)); a += b; d += ((b ^ c) & a) ^ c; d += x[sh + 1] + t[1]; d = (d << S12) | (d >> (32 - S12)); d += a; c += ((a ^ b) & d) ^ b; c += x[sh + 2] + t[2]; c = (c << S13) | (c >> (32 - S13)); c += d; b += ((d ^ a) & c) ^ a; b += x[sh + 3] + t[3]; b = (b << S14) | (b >> (32 - S14)); b += c; sh += 4; } sh = 1; for(; sh != 1+20*4; t += 4){ a += ((b ^ c) & d) ^ c; a += x[sh & 0xf] + t[0]; a = (a << S21) | (a >> (32 - S21)); a += b; d += ((a ^ b) & c) ^ b; d += x[(sh + 5) & 0xf] + t[1]; d = (d << S22) | (d >> (32 - S22)); d += a; c += ((d ^ a) & b) ^ a; c += x[(sh + 10) & 0xf] + t[2]; c = (c << S23) | (c >> (32 - S23)); c += d; b += ((c ^ d) & a) ^ d; b += x[(sh + 15) & 0xf] + t[3]; b = (b << S24) | (b >> (32 - S24)); b += c; sh += 20; } sh = 5; for(; sh != 5+12*4; t += 4){ a += b ^ c ^ d; a += x[sh & 0xf] + t[0]; a = (a << S31) | (a >> (32 - S31)); a += b; d += a ^ b ^ c; d += x[(sh + 3) & 0xf] + t[1]; d = (d << S32) | (d >> (32 - S32)); d += a; c += d ^ a ^ b; c += x[(sh + 6) & 0xf] + t[2]; c = (c << S33) | (c >> (32 - S33)); c += d; b += c ^ d ^ a; b += x[(sh + 9) & 0xf] + t[3]; b = (b << S34) | (b >> (32 - S34)); b += c; sh += 12; } sh = 0; for(; sh != 28*4; t += 4){ a += c ^ (b | ~d); a += x[sh & 0xf] + t[0]; a = (a << S41) | (a >> (32 - S41)); a += b; d += b ^ (a | ~c); d += x[(sh + 7) & 0xf] + t[1]; d = (d << S42) | (d >> (32 - S42)); d += a; c += a ^ (d | ~b); c += x[(sh + 14) & 0xf] + t[2]; c = (c << S43) | (c >> (32 - S43)); c += d; b += d ^ (c | ~a); b += x[(sh + 21) & 0xf] + t[3]; b = (b << S44) | (b >> (32 - S44)); b += c; sh += 28; } s[0] += a; s[1] += b; s[2] += c; s[3] += d; } } /* * decodes input (uchar) into output (u32int). Assumes len is * a multiple of 4. */ static void decode(u32int *output, uchar *input, ulong len) { uchar *e; for(e = input+len; input < e; input += 4) *output++ = input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24); } drawterm-20170818/posix-port/sha1block.c000066400000000000000000000111461314554504700177650ustar00rootroot00000000000000#include #include #include void _sha1block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, e, x; uchar *end; u32int *wp, *wend; u32int w[80]; /* at this point, we have a multiple of 64 bytes */ for(end = p+len; p < end;){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; e = s[4]; wend = w + 15; for(wp = w; wp < wend; wp += 5){ wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); wp[1] = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7]; d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); wp[2] = (p[8]<<24) | (p[9]<<16) | (p[10]<<8) | p[11]; c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); wp[3] = (p[12]<<24) | (p[13]<<16) | (p[14]<<8) | p[15]; b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); wp[4] = (p[16]<<24) | (p[17]<<16) | (p[18]<<8) | p[19]; a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); p += 20; } wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); wp += 5; p += 4; wend = w + 40; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x6ed9eba1 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x6ed9eba1 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x6ed9eba1 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x6ed9eba1 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x6ed9eba1 + (c^d^e); c = (c<<30)|(c>>2); } wend = w + 60; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x8f1bbcdc + ((b&c)|((b|c)&d)); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x8f1bbcdc + ((a&b)|((a|b)&c)); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x8f1bbcdc + ((e&a)|((e|a)&b)); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x8f1bbcdc + ((d&e)|((d|e)&a)); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x8f1bbcdc + ((c&d)|((c|d)&e)); c = (c<<30)|(c>>2); } wend = w + 80; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0xca62c1d6 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0xca62c1d6 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0xca62c1d6 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0xca62c1d6 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0xca62c1d6 + (c^d^e); c = (c<<30)|(c>>2); } /* save state */ s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; } } drawterm-20170818/posix-power/000077500000000000000000000000001314554504700161175ustar00rootroot00000000000000drawterm-20170818/posix-power/Makefile000066400000000000000000000004431314554504700175600ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=../libmachdep.a OFILES=\ getcallerpc.$O\ md5block.$O\ sha1block.$O\ tas.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c %.$O: %.s $(AS) -o $*.$O $*.s %.s: %.spp cpp $*.spp >$*.s drawterm-20170818/posix-power/getcallerpc.c000066400000000000000000000001361314554504700205500ustar00rootroot00000000000000#include "u.h" #include "libc.h" uintptr getcallerpc(void *a) { return ((uintptr*)a)[-1]; } drawterm-20170818/posix-power/md5block.c000066400000000000000000000116501314554504700177660ustar00rootroot00000000000000#include #include #include /* * rfc1321 requires that I include this. The code is new. The constants * all come from the rfc (hence the copyright). We trade a table for the * macros in rfc. The total size is a lot less. -- presotto * * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it * is identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided * that such works are identified as "derived from the RSA Data * Security, Inc. MD5 Message-Digest Algorithm" in all material * mentioning or referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software forany particular purpose. It is provided "as is" * without express or implied warranty of any kind. * These notices must be retained in any copies of any part of this * documentation and/or software. */ /* * Rotate ammounts used in the algorithm */ enum { S11= 7, S12= 12, S13= 17, S14= 22, S21= 5, S22= 9, S23= 14, S24= 20, S31= 4, S32= 11, S33= 16, S34= 23, S41= 6, S42= 10, S43= 15, S44= 21, }; static u32int md5tab[] = { /* round 1 */ /*[0]*/ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, /* round 2 */ /*[16]*/0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, /* round 3 */ /*[32]*/0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, /* round 4 */ /*[48]*/0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; static void decode(u32int*, uchar*, ulong); extern void _md5block(uchar *p, ulong len, u32int *s); void _md5block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, sh; u32int *t; uchar *end; u32int x[16]; for(end = p+len; p < end; p += 64){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; decode(x, p, 64); t = md5tab; sh = 0; for(; sh != 16; t += 4){ a += ((c ^ d) & b) ^ d; a += x[sh] + t[0]; a = (a << S11) | (a >> (32 - S11)); a += b; d += ((b ^ c) & a) ^ c; d += x[sh + 1] + t[1]; d = (d << S12) | (d >> (32 - S12)); d += a; c += ((a ^ b) & d) ^ b; c += x[sh + 2] + t[2]; c = (c << S13) | (c >> (32 - S13)); c += d; b += ((d ^ a) & c) ^ a; b += x[sh + 3] + t[3]; b = (b << S14) | (b >> (32 - S14)); b += c; sh += 4; } sh = 1; for(; sh != 1+20*4; t += 4){ a += ((b ^ c) & d) ^ c; a += x[sh & 0xf] + t[0]; a = (a << S21) | (a >> (32 - S21)); a += b; d += ((a ^ b) & c) ^ b; d += x[(sh + 5) & 0xf] + t[1]; d = (d << S22) | (d >> (32 - S22)); d += a; c += ((d ^ a) & b) ^ a; c += x[(sh + 10) & 0xf] + t[2]; c = (c << S23) | (c >> (32 - S23)); c += d; b += ((c ^ d) & a) ^ d; b += x[(sh + 15) & 0xf] + t[3]; b = (b << S24) | (b >> (32 - S24)); b += c; sh += 20; } sh = 5; for(; sh != 5+12*4; t += 4){ a += b ^ c ^ d; a += x[sh & 0xf] + t[0]; a = (a << S31) | (a >> (32 - S31)); a += b; d += a ^ b ^ c; d += x[(sh + 3) & 0xf] + t[1]; d = (d << S32) | (d >> (32 - S32)); d += a; c += d ^ a ^ b; c += x[(sh + 6) & 0xf] + t[2]; c = (c << S33) | (c >> (32 - S33)); c += d; b += c ^ d ^ a; b += x[(sh + 9) & 0xf] + t[3]; b = (b << S34) | (b >> (32 - S34)); b += c; sh += 12; } sh = 0; for(; sh != 28*4; t += 4){ a += c ^ (b | ~d); a += x[sh & 0xf] + t[0]; a = (a << S41) | (a >> (32 - S41)); a += b; d += b ^ (a | ~c); d += x[(sh + 7) & 0xf] + t[1]; d = (d << S42) | (d >> (32 - S42)); d += a; c += a ^ (d | ~b); c += x[(sh + 14) & 0xf] + t[2]; c = (c << S43) | (c >> (32 - S43)); c += d; b += d ^ (c | ~a); b += x[(sh + 21) & 0xf] + t[3]; b = (b << S44) | (b >> (32 - S44)); b += c; sh += 28; } s[0] += a; s[1] += b; s[2] += c; s[3] += d; } } /* * decodes input (uchar) into output (u32int). Assumes len is * a multiple of 4. */ static void decode(u32int *output, uchar *input, ulong len) { uchar *e; for(e = input+len; input < e; input += 4) *output++ = input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24); } drawterm-20170818/posix-power/sha1block.c000066400000000000000000000111461314554504700201350ustar00rootroot00000000000000#include #include #include void _sha1block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, e, x; uchar *end; u32int *wp, *wend; u32int w[80]; /* at this point, we have a multiple of 64 bytes */ for(end = p+len; p < end;){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; e = s[4]; wend = w + 15; for(wp = w; wp < wend; wp += 5){ wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); wp[1] = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7]; d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); wp[2] = (p[8]<<24) | (p[9]<<16) | (p[10]<<8) | p[11]; c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); wp[3] = (p[12]<<24) | (p[13]<<16) | (p[14]<<8) | p[15]; b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); wp[4] = (p[16]<<24) | (p[17]<<16) | (p[18]<<8) | p[19]; a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); p += 20; } wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); wp += 5; p += 4; wend = w + 40; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x6ed9eba1 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x6ed9eba1 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x6ed9eba1 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x6ed9eba1 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x6ed9eba1 + (c^d^e); c = (c<<30)|(c>>2); } wend = w + 60; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x8f1bbcdc + ((b&c)|((b|c)&d)); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x8f1bbcdc + ((a&b)|((a|b)&c)); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x8f1bbcdc + ((e&a)|((e|a)&b)); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x8f1bbcdc + ((d&e)|((d|e)&a)); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x8f1bbcdc + ((c&d)|((c|d)&e)); c = (c<<30)|(c>>2); } wend = w + 80; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0xca62c1d6 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0xca62c1d6 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0xca62c1d6 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0xca62c1d6 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0xca62c1d6 + (c^d^e); c = (c<<30)|(c>>2); } /* save state */ s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; } } drawterm-20170818/posix-power/tas.c000066400000000000000000000016571314554504700170630ustar00rootroot00000000000000#include "u.h" #include "libc.h" /* * first argument (l) is in r3 at entry. * r3 contains return value upon return. */ int tas(long *x) { int v; /* * this __asm__ works with gcc 2.95.2 (mac os x 10.1). * this assembly language destroys r0 (0), some other register (v), * r4 (x) and r5 (temp). */ __asm__("\n sync\n" " li r0,0\n" " mr r4,%1 /* &l->val */\n" " lis r5,0xdead /* assemble constant 0xdeaddead */\n" " ori r5,r5,0xdead /* \" */\n" "tas1:\n" " dcbf r4,r0 /* cache flush; \"fix for 603x bug\" */\n" " lwarx %0,r4,r0 /* v = l->val with reservation */\n" " cmp cr0,0,%0,r0 /* v == 0 */\n" " bne tas0\n" " stwcx. r5,r4,r0 /* if (l->val same) l->val = 0xdeaddead */\n" " bne tas1\n" "tas0:\n" " sync\n" " isync\n" : "=r" (v) : "r" (x) : "cc", "memory", "r0", "r4", "r5" ); switch(v) { case 0: return 0; case 0xdeaddead: return 1; default: print("tas: corrupted 0x%lux\n", v); } return 0; } drawterm-20170818/posix-sun4u/000077500000000000000000000000001314554504700160415ustar00rootroot00000000000000drawterm-20170818/posix-sun4u/Makefile000066400000000000000000000004441314554504700175030ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=../libmachdep.a OFILES=\ getcallerpc.$O\ md5block.$O\ sha1block.$O\ tas.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c %.$O: %.s $(AS) -o $*.$O $*.s %.s: %.spp cpp $*.spp >$*.s drawterm-20170818/posix-sun4u/getcallerpc.c000066400000000000000000000001331314554504700204670ustar00rootroot00000000000000#include "u.h" #include "libc.h" ulong getcallerpc(void *a) { return ((ulong*)a)[-1]; } drawterm-20170818/posix-sun4u/md5block.c000066400000000000000000000116501314554504700177100ustar00rootroot00000000000000#include #include #include /* * rfc1321 requires that I include this. The code is new. The constants * all come from the rfc (hence the copyright). We trade a table for the * macros in rfc. The total size is a lot less. -- presotto * * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it * is identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided * that such works are identified as "derived from the RSA Data * Security, Inc. MD5 Message-Digest Algorithm" in all material * mentioning or referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software forany particular purpose. It is provided "as is" * without express or implied warranty of any kind. * These notices must be retained in any copies of any part of this * documentation and/or software. */ /* * Rotate ammounts used in the algorithm */ enum { S11= 7, S12= 12, S13= 17, S14= 22, S21= 5, S22= 9, S23= 14, S24= 20, S31= 4, S32= 11, S33= 16, S34= 23, S41= 6, S42= 10, S43= 15, S44= 21, }; static u32int md5tab[] = { /* round 1 */ /*[0]*/ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, /* round 2 */ /*[16]*/0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, /* round 3 */ /*[32]*/0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, /* round 4 */ /*[48]*/0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; static void decode(u32int*, uchar*, ulong); extern void _md5block(uchar *p, ulong len, u32int *s); void _md5block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, sh; u32int *t; uchar *end; u32int x[16]; for(end = p+len; p < end; p += 64){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; decode(x, p, 64); t = md5tab; sh = 0; for(; sh != 16; t += 4){ a += ((c ^ d) & b) ^ d; a += x[sh] + t[0]; a = (a << S11) | (a >> (32 - S11)); a += b; d += ((b ^ c) & a) ^ c; d += x[sh + 1] + t[1]; d = (d << S12) | (d >> (32 - S12)); d += a; c += ((a ^ b) & d) ^ b; c += x[sh + 2] + t[2]; c = (c << S13) | (c >> (32 - S13)); c += d; b += ((d ^ a) & c) ^ a; b += x[sh + 3] + t[3]; b = (b << S14) | (b >> (32 - S14)); b += c; sh += 4; } sh = 1; for(; sh != 1+20*4; t += 4){ a += ((b ^ c) & d) ^ c; a += x[sh & 0xf] + t[0]; a = (a << S21) | (a >> (32 - S21)); a += b; d += ((a ^ b) & c) ^ b; d += x[(sh + 5) & 0xf] + t[1]; d = (d << S22) | (d >> (32 - S22)); d += a; c += ((d ^ a) & b) ^ a; c += x[(sh + 10) & 0xf] + t[2]; c = (c << S23) | (c >> (32 - S23)); c += d; b += ((c ^ d) & a) ^ d; b += x[(sh + 15) & 0xf] + t[3]; b = (b << S24) | (b >> (32 - S24)); b += c; sh += 20; } sh = 5; for(; sh != 5+12*4; t += 4){ a += b ^ c ^ d; a += x[sh & 0xf] + t[0]; a = (a << S31) | (a >> (32 - S31)); a += b; d += a ^ b ^ c; d += x[(sh + 3) & 0xf] + t[1]; d = (d << S32) | (d >> (32 - S32)); d += a; c += d ^ a ^ b; c += x[(sh + 6) & 0xf] + t[2]; c = (c << S33) | (c >> (32 - S33)); c += d; b += c ^ d ^ a; b += x[(sh + 9) & 0xf] + t[3]; b = (b << S34) | (b >> (32 - S34)); b += c; sh += 12; } sh = 0; for(; sh != 28*4; t += 4){ a += c ^ (b | ~d); a += x[sh & 0xf] + t[0]; a = (a << S41) | (a >> (32 - S41)); a += b; d += b ^ (a | ~c); d += x[(sh + 7) & 0xf] + t[1]; d = (d << S42) | (d >> (32 - S42)); d += a; c += a ^ (d | ~b); c += x[(sh + 14) & 0xf] + t[2]; c = (c << S43) | (c >> (32 - S43)); c += d; b += d ^ (c | ~a); b += x[(sh + 21) & 0xf] + t[3]; b = (b << S44) | (b >> (32 - S44)); b += c; sh += 28; } s[0] += a; s[1] += b; s[2] += c; s[3] += d; } } /* * decodes input (uchar) into output (u32int). Assumes len is * a multiple of 4. */ static void decode(u32int *output, uchar *input, ulong len) { uchar *e; for(e = input+len; input < e; input += 4) *output++ = input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24); } drawterm-20170818/posix-sun4u/sha1block.c000066400000000000000000000111461314554504700200570ustar00rootroot00000000000000#include #include #include void _sha1block(uchar *p, ulong len, u32int *s) { u32int a, b, c, d, e, x; uchar *end; u32int *wp, *wend; u32int w[80]; /* at this point, we have a multiple of 64 bytes */ for(end = p+len; p < end;){ a = s[0]; b = s[1]; c = s[2]; d = s[3]; e = s[4]; wend = w + 15; for(wp = w; wp < wend; wp += 5){ wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); wp[1] = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7]; d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); wp[2] = (p[8]<<24) | (p[9]<<16) | (p[10]<<8) | p[11]; c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); wp[3] = (p[12]<<24) | (p[13]<<16) | (p[14]<<8) | p[15]; b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); wp[4] = (p[16]<<24) | (p[17]<<16) | (p[18]<<8) | p[19]; a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); p += 20; } wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; e += ((a<<5) | (a>>27)) + wp[0]; e += 0x5a827999 + (((c^d)&b)^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x5a827999 + (((b^c)&a)^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x5a827999 + (((a^b)&e)^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x5a827999 + (((e^a)&d)^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x5a827999 + (((d^e)&c)^e); c = (c<<30)|(c>>2); wp += 5; p += 4; wend = w + 40; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x6ed9eba1 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x6ed9eba1 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x6ed9eba1 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x6ed9eba1 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x6ed9eba1 + (c^d^e); c = (c<<30)|(c>>2); } wend = w + 60; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0x8f1bbcdc + ((b&c)|((b|c)&d)); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0x8f1bbcdc + ((a&b)|((a|b)&c)); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0x8f1bbcdc + ((e&a)|((e|a)&b)); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0x8f1bbcdc + ((d&e)|((d|e)&a)); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0x8f1bbcdc + ((c&d)|((c|d)&e)); c = (c<<30)|(c>>2); } wend = w + 80; for(; wp < wend; wp += 5){ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16]; wp[0] = (x<<1) | (x>>31); e += ((a<<5) | (a>>27)) + wp[0]; e += 0xca62c1d6 + (b^c^d); b = (b<<30)|(b>>2); x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15]; wp[1] = (x<<1) | (x>>31); d += ((e<<5) | (e>>27)) + wp[1]; d += 0xca62c1d6 + (a^b^c); a = (a<<30)|(a>>2); x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14]; wp[2] = (x<<1) | (x>>31); c += ((d<<5) | (d>>27)) + wp[2]; c += 0xca62c1d6 + (e^a^b); e = (e<<30)|(e>>2); x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13]; wp[3] = (x<<1) | (x>>31); b += ((c<<5) | (c>>27)) + wp[3]; b += 0xca62c1d6 + (d^e^a); d = (d<<30)|(d>>2); x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12]; wp[4] = (x<<1) | (x>>31); a += ((b<<5) | (b>>27)) + wp[4]; a += 0xca62c1d6 + (c^d^e); c = (c<<30)|(c>>2); } /* save state */ s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; } } drawterm-20170818/posix-sun4u/tas.s000066400000000000000000000000521314554504700170110ustar00rootroot00000000000000.globl tas tas: retl ldstub [%o0], %o0 drawterm-20170818/readcons.c000066400000000000000000000034621314554504700155720ustar00rootroot00000000000000#include #include #include "drawterm.h" void* erealloc(void *v, ulong n) { v = realloc(v, n); if(v == nil) sysfatal("out of memory"); return v; } char* estrdup(char *s) { s = strdup(s); if(s == nil) sysfatal("out of memory"); return s; } char* estrappend(char *s, char *fmt, ...) { char *t; va_list arg; va_start(arg, fmt); t = vsmprint(fmt, arg); if(t == nil) sysfatal("out of memory"); va_end(arg); s = erealloc(s, strlen(s)+strlen(t)+1); strcat(s, t); free(t); return s; } /* * prompt for a string with a possible default response */ char* readcons(char *prompt, char *def, int raw) { int fdin, fdout, ctl, n; char line[10]; char *s; fdin = open("/dev/cons", OREAD); if(fdin < 0) fdin = 0; fdout = open("/dev/cons", OWRITE); if(fdout < 0) fdout = 1; if(def != nil) fprint(fdout, "%s[%s]: ", prompt, def); else fprint(fdout, "%s: ", prompt); if(raw){ ctl = open("/dev/consctl", OWRITE); if(ctl >= 0) write(ctl, "rawon", 5); } else ctl = -1; s = estrdup(""); for(;;){ n = read(fdin, line, 1); if(n == 0){ Error: close(fdin); close(fdout); if(ctl >= 0) close(ctl); free(s); return nil; } if(n < 0) goto Error; if(line[0] == 0x7f) goto Error; if(n == 0 || line[0] == '\n' || line[0] == '\r'){ if(raw){ write(ctl, "rawoff", 6); write(fdout, "\n", 1); } close(ctl); close(fdin); close(fdout); if(*s == 0 && def != nil) s = estrappend(s, "%s", def); return s; } if(line[0] == '\b'){ if(strlen(s) > 0) s[strlen(s)-1] = 0; } else if(line[0] == 0x15) { /* ^U: line kill */ if(def != nil) fprint(fdout, "\n%s[%s]: ", prompt, def); else fprint(fdout, "\n%s: ", prompt); s[0] = 0; } else { s = estrappend(s, "%c", line[0]); } } return nil; /* not reached */ } drawterm-20170818/resource.h000066400000000000000000000007111314554504700156220ustar00rootroot00000000000000//{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by drawterm.rc // #define IDI_ICON1 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif drawterm-20170818/secstore.c000066400000000000000000000365761314554504700156370ustar00rootroot00000000000000/* * Various files from /sys/src/cmd/auth/secstore, just enough * to download a file at boot time. */ #include #include #include #include #include "drawterm.h" static void* emalloc(ulong n) { return mallocz(n, 1); } enum{ CHK = 16}; enum{ MAXFILESIZE = 10*1024*1024 }; enum{// PW status bits Enabled = (1<<0), STA = (1<<1), // extra SecurID step }; static char testmess[] = "__secstore\tPAK\nC=%s\nm=0\n"; int secdial(char *secstore) { char *p, buf[80], *f[3]; int fd, nf; p = secstore; /* take it from writehostowner, if set there */ if(*p == 0) /* else use the authserver */ p = "$auth"; /* translate $auth ourselves. * authaddr is something like il!host!566 or tcp!host!567. * extract host, accounting for a change of format to something * like il!host or tcp!host or host. */ if(strcmp(p, "$auth")==0){ if(authserver == nil) return -1; strecpy(buf, buf+sizeof buf, authserver); nf = getfields(buf, f, nelem(f), 0, "!"); switch(nf){ default: return -1; case 1: p = f[0]; break; case 2: case 3: p = f[1]; break; } } fd = dial(netmkaddr(p, "tcp", "5356"), 0, 0, 0); if(fd >= 0) return fd; return -1; } int havesecstore(char *addr, char *owner) { int m, n, fd; uchar buf[500]; n = snprint((char*)buf, sizeof buf, testmess, owner); hnputs(buf, 0x8000+n-2); fd = secdial(addr); if(fd < 0) return 0; if(write(fd, buf, n) != n || readn(fd, buf, 2) != 2){ close(fd); return 0; } n = ((buf[0]&0x7f)<<8) + buf[1]; if(n+1 > sizeof buf){ werrstr("implausibly large count %d", n); close(fd); return 0; } m = readn(fd, buf, n); close(fd); if(m != n){ if(m >= 0) werrstr("short read from secstore"); return 0; } buf[n] = 0; if(strcmp((char*)buf, "!account expired") == 0){ werrstr("account expired"); return 0; } return strcmp((char*)buf, "!account exists") == 0; } // delimited, authenticated, encrypted connection enum{ Maxmsg=4096 }; // messages > Maxmsg bytes are truncated typedef struct SConn SConn; extern SConn* newSConn(int); // arg is open file descriptor struct SConn{ void *chan; int secretlen; int (*secret)(SConn*, uchar*, int);// int (*read)(SConn*, uchar*, int); // <0 if error; errmess in buffer int (*write)(SConn*, uchar*, int); void (*free)(SConn*); // also closes file descriptor }; // secret(s,b,dir) sets secret for digest, encrypt, using the secretlen // bytes in b to form keys for the two directions; // set dir=0 in client, dir=1 in server // error convention: write !message in-band #define readstr secstore_readstr static void writerr(SConn*, char*); static int readstr(SConn*, char*); // call with buf of size Maxmsg+1 // returns -1 upon error, with error message in buf typedef struct ConnState { uchar secret[SHA1dlen]; ulong seqno; RC4state rc4; } ConnState; typedef struct SS{ int fd; // file descriptor for read/write of encrypted data int alg; // if nonzero, "alg sha rc4_128" ConnState in, out; } SS; static int SC_secret(SConn *conn, uchar *sigma, int direction) { SS *ss = (SS*)(conn->chan); int nsigma = conn->secretlen; if(direction != 0){ hmac_sha1(sigma, nsigma, (uchar*)"one", 3, ss->out.secret, nil); hmac_sha1(sigma, nsigma, (uchar*)"two", 3, ss->in.secret, nil); }else{ hmac_sha1(sigma, nsigma, (uchar*)"two", 3, ss->out.secret, nil); hmac_sha1(sigma, nsigma, (uchar*)"one", 3, ss->in.secret, nil); } setupRC4state(&ss->in.rc4, ss->in.secret, 16); // restrict to 128 bits setupRC4state(&ss->out.rc4, ss->out.secret, 16); ss->alg = 1; return 0; } static void hash(uchar secret[SHA1dlen], uchar *data, int len, int seqno, uchar d[SHA1dlen]) { DigestState sha; uchar seq[4]; seq[0] = seqno>>24; seq[1] = seqno>>16; seq[2] = seqno>>8; seq[3] = seqno; memset(&sha, 0, sizeof sha); sha1(secret, SHA1dlen, nil, &sha); sha1(data, len, nil, &sha); sha1(seq, 4, d, &sha); } static int verify(uchar secret[SHA1dlen], uchar *data, int len, int seqno, uchar d[SHA1dlen]) { DigestState sha; uchar seq[4]; uchar digest[SHA1dlen]; seq[0] = seqno>>24; seq[1] = seqno>>16; seq[2] = seqno>>8; seq[3] = seqno; memset(&sha, 0, sizeof sha); sha1(secret, SHA1dlen, nil, &sha); sha1(data, len, nil, &sha); sha1(seq, 4, digest, &sha); return memcmp(d, digest, SHA1dlen); } static int SC_read(SConn *conn, uchar *buf, int n) { SS *ss = (SS*)(conn->chan); uchar count[2], digest[SHA1dlen]; int len, nr; if(read(ss->fd, count, 2) != 2 || (count[0]&0x80) == 0){ werrstr("!SC_read invalid count"); return -1; } len = (count[0]&0x7f)<<8 | count[1]; // SSL-style count; no pad if(ss->alg){ len -= SHA1dlen; if(len <= 0 || readn(ss->fd, digest, SHA1dlen) != SHA1dlen){ werrstr("!SC_read missing sha1"); return -1; } if(len > n || readn(ss->fd, buf, len) != len){ werrstr("!SC_read missing data"); return -1; } rc4(&ss->in.rc4, digest, SHA1dlen); rc4(&ss->in.rc4, buf, len); if(verify(ss->in.secret, buf, len, ss->in.seqno, digest) != 0){ werrstr("!SC_read integrity check failed"); return -1; } }else{ if(len <= 0 || len > n){ werrstr("!SC_read implausible record length"); return -1; } if( (nr = readn(ss->fd, buf, len)) != len){ werrstr("!SC_read expected %d bytes, but got %d", len, nr); return -1; } } ss->in.seqno++; return len; } static int SC_write(SConn *conn, uchar *buf, int n) { SS *ss = (SS*)(conn->chan); uchar count[2], digest[SHA1dlen]; int len; if(n <= 0 || n > Maxmsg+1){ werrstr("!SC_write invalid n %d", n); return -1; } len = n; if(ss->alg) len += SHA1dlen; count[0] = 0x80 | len>>8; count[1] = len; if(write(ss->fd, count, 2) != 2){ werrstr("!SC_write invalid count"); return -1; } if(ss->alg){ hash(ss->out.secret, buf, n, ss->out.seqno, digest); rc4(&ss->out.rc4, digest, SHA1dlen); rc4(&ss->out.rc4, buf, n); if(write(ss->fd, digest, SHA1dlen) != SHA1dlen || write(ss->fd, buf, n) != n){ werrstr("!SC_write error on send"); return -1; } }else{ if(write(ss->fd, buf, n) != n){ werrstr("!SC_write error on send"); return -1; } } ss->out.seqno++; return n; } static void SC_free(SConn *conn) { SS *ss = (SS*)(conn->chan); close(ss->fd); free(ss); free(conn); } SConn* newSConn(int fd) { SS *ss; SConn *conn; if(fd < 0) return nil; ss = (SS*)emalloc(sizeof(*ss)); conn = (SConn*)emalloc(sizeof(*conn)); ss->fd = fd; ss->alg = 0; conn->chan = (void*)ss; conn->secretlen = SHA1dlen; conn->free = SC_free; conn->secret = SC_secret; conn->read = SC_read; conn->write = SC_write; return conn; } static void writerr(SConn *conn, char *s) { char buf[Maxmsg]; snprint(buf, Maxmsg, "!%s", s); conn->write(conn, (uchar*)buf, strlen(buf)); } static int readstr(SConn *conn, char *s) { int n; n = conn->read(conn, (uchar*)s, Maxmsg); if(n >= 0){ s[n] = 0; if(s[0] == '!'){ memmove(s, s+1, n); n = -1; } }else{ strcpy(s, "read error"); } return n; } static char* getfile(SConn *conn, uchar *key, int nkey) { char *buf; int nbuf, n, nr, len; char s[Maxmsg+1], *gf; uchar skey[SHA1dlen], ib[Maxmsg+CHK], *ibr, *ibw; AESstate aes; DigestState *sha; gf = "factotum"; memset(&aes, 0, sizeof aes); snprint(s, Maxmsg, "GET %s\n", gf); conn->write(conn, (uchar*)s, strlen(s)); /* get file size */ s[0] = '\0'; if(readstr(conn, s) < 0){ werrstr("secstore: %r"); return nil; } if((len = atoi(s)) < 0){ werrstr("secstore: remote file %s does not exist", gf); return nil; }else if(len > MAXFILESIZE){//assert werrstr("secstore: implausible file size %d for %s", len, gf); return nil; } ibr = ibw = ib; buf = nil; nbuf = 0; for(nr=0; nr < len;){ if((n = conn->read(conn, ibw, Maxmsg)) <= 0){ werrstr("secstore: empty file chunk n=%d nr=%d len=%d: %r", n, nr, len); return nil; } nr += n; ibw += n; if(!aes.setup){ /* first time, read 16 byte IV */ if(n < 16){ werrstr("secstore: no IV in file"); return nil; } sha = sha1((uchar*)"aescbc file", 11, nil, nil); sha1(key, nkey, skey, sha); setupAESstate(&aes, skey, AESbsize, ibr); memset(skey, 0, sizeof skey); ibr += AESbsize; n -= AESbsize; } aesCBCdecrypt(ibw-n, n, &aes); n = ibw-ibr-CHK; if(n > 0){ buf = realloc(buf, nbuf+n+1); if(buf == nil) sysfatal("out of memory"); memmove(buf+nbuf, ibr, n); nbuf += n; ibr += n; } memmove(ib, ibr, ibw-ibr); ibw = ib + (ibw-ibr); ibr = ib; } n = ibw-ibr; if((n != CHK) || (memcmp(ib, "XXXXXXXXXXXXXXXX", CHK) != 0)){ werrstr("secstore: decrypted file failed to authenticate!"); free(buf); return nil; } if(nbuf == 0){ werrstr("secstore got empty file"); return nil; } buf[nbuf] = '\0'; return buf; } static char VERSION[] = "secstore"; typedef struct PAKparams{ mpint *q, *p, *r, *g; } PAKparams; static PAKparams *pak; // This group was generated by the seed EB7B6E35F7CD37B511D96C67D6688CC4DD440E1E. static void initPAKparams(void) { if(pak) return; pak = (PAKparams*)emalloc(sizeof(*pak)); pak->q = strtomp("E0F0EF284E10796C5A2A511E94748BA03C795C13", nil, 16, nil); pak->p = strtomp("C41CFBE4D4846F67A3DF7DE9921A49D3B42DC33728427AB159CEC8CBBD" "B12B5F0C244F1A734AEB9840804EA3C25036AD1B61AFF3ABBC247CD4B384224567A86" "3A6F020E7EE9795554BCD08ABAD7321AF27E1E92E3DB1C6E7E94FAAE590AE9C48F96D9" "3D178E809401ABE8A534A1EC44359733475A36A70C7B425125062B1142D", nil, 16, nil); pak->r = strtomp("DF310F4E54A5FEC5D86D3E14863921E834113E060F90052AD332B3241CEF" "2497EFA0303D6344F7C819691A0F9C4A773815AF8EAECFB7EC1D98F039F17A32A7E887" "D97251A927D093F44A55577F4D70444AEBD06B9B45695EC23962B175F266895C67D21" "C4656848614D888A4", nil, 16, nil); pak->g = strtomp("2F1C308DC46B9A44B52DF7DACCE1208CCEF72F69C743ADD4D2327173444" "ED6E65E074694246E07F9FD4AE26E0FDDD9F54F813C40CB9BCD4338EA6F242AB94CD41" "0E676C290368A16B1A3594877437E516C53A6EEE5493A038A017E955E218E7819734E3E" "2A6E0BAE08B14258F8C03CC1B30E0DDADFCF7CEDF0727684D3D255F1", nil, 16, nil); } // H = (sha(ver,C,sha(passphrase)))^r mod p, // a hash function expensive to attack by brute force. static void longhash(char *ver, char *C, uchar *passwd, mpint *H) { uchar *Cp; int i, n, nver, nC; uchar buf[140], key[1]; nver = strlen(ver); nC = strlen(C); n = nver + nC + SHA1dlen; Cp = (uchar*)emalloc(n); memmove(Cp, ver, nver); memmove(Cp+nver, C, nC); memmove(Cp+nver+nC, passwd, SHA1dlen); for(i = 0; i < 7; i++){ key[0] = 'A'+i; hmac_sha1(Cp, n, key, sizeof key, buf+i*SHA1dlen, nil); } memset(Cp, 0, n); free(Cp); betomp(buf, sizeof buf, H); mpmod(H, pak->p, H); mpexp(H, pak->r, pak->p, H); } // Hi = H^-1 mod p static char * PAK_Hi(char *C, char *passphrase, mpint *H, mpint *Hi) { uchar passhash[SHA1dlen]; sha1((uchar *)passphrase, strlen(passphrase), passhash, nil); initPAKparams(); longhash(VERSION, C, passhash, H); mpinvert(H, pak->p, Hi); return mptoa(Hi, 64, nil, 0); } // another, faster, hash function for each party to // confirm that the other has the right secrets. static void shorthash(char *mess, char *C, char *S, char *m, char *mu, char *sigma, char *Hi, uchar *digest) { SHA1state *state; state = sha1((uchar*)mess, strlen(mess), 0, 0); state = sha1((uchar*)C, strlen(C), 0, state); state = sha1((uchar*)S, strlen(S), 0, state); state = sha1((uchar*)m, strlen(m), 0, state); state = sha1((uchar*)mu, strlen(mu), 0, state); state = sha1((uchar*)sigma, strlen(sigma), 0, state); state = sha1((uchar*)Hi, strlen(Hi), 0, state); state = sha1((uchar*)mess, strlen(mess), 0, state); state = sha1((uchar*)C, strlen(C), 0, state); state = sha1((uchar*)S, strlen(S), 0, state); state = sha1((uchar*)m, strlen(m), 0, state); state = sha1((uchar*)mu, strlen(mu), 0, state); state = sha1((uchar*)sigma, strlen(sigma), 0, state); sha1((uchar*)Hi, strlen(Hi), digest, state); } // On input, conn provides an open channel to the server; // C is the name this client calls itself; // pass is the user's passphrase // On output, session secret has been set in conn // (unless return code is negative, which means failure). // If pS is not nil, it is set to the (alloc'd) name the server calls itself. static int PAKclient(SConn *conn, char *C, char *pass, char **pS) { char *mess, *mess2, *eol, *S, *hexmu, *ks, *hexm, *hexsigma = nil, *hexHi; char kc[2*SHA1dlen+1]; uchar digest[SHA1dlen]; int rc = -1, n; mpint *x, *m = mpnew(0), *mu = mpnew(0), *sigma = mpnew(0); mpint *H = mpnew(0), *Hi = mpnew(0); hexHi = PAK_Hi(C, pass, H, Hi); // random 1<=x<=q-1; send C, m=g**x H x = mprand(164, genrandom, nil); mpmod(x, pak->q, x); if(mpcmp(x, mpzero) == 0) mpassign(mpone, x); mpexp(pak->g, x, pak->p, m); mpmul(m, H, m); mpmod(m, pak->p, m); hexm = mptoa(m, 64, nil, 0); mess = (char*)emalloc(2*Maxmsg+2); mess2 = mess+Maxmsg+1; snprint(mess, Maxmsg, "%s\tPAK\nC=%s\nm=%s\n", VERSION, C, hexm); conn->write(conn, (uchar*)mess, strlen(mess)); // recv g**y, S, check hash1(g**xy) if(readstr(conn, mess) < 0){ fprint(2, "error: %s\n", mess); writerr(conn, "couldn't read g**y"); goto done; } eol = strchr(mess, '\n'); if(strncmp("mu=", mess, 3) != 0 || !eol || strncmp("\nk=", eol, 3) != 0){ writerr(conn, "verifier syntax error"); goto done; } hexmu = mess+3; *eol = 0; ks = eol+3; eol = strchr(ks, '\n'); if(!eol || strncmp("\nS=", eol, 3) != 0){ writerr(conn, "verifier syntax error for secstore 1.0"); goto done; } *eol = 0; S = eol+3; eol = strchr(S, '\n'); if(!eol){ writerr(conn, "verifier syntax error for secstore 1.0"); goto done; } *eol = 0; if(pS) *pS = strdup(S); strtomp(hexmu, nil, 64, mu); mpexp(mu, x, pak->p, sigma); hexsigma = mptoa(sigma, 64, nil, 0); shorthash("server", C, S, hexm, hexmu, hexsigma, hexHi, digest); enc64(kc, sizeof kc, digest, SHA1dlen); if(strcmp(ks, kc) != 0){ writerr(conn, "verifier didn't match"); goto done; } // send hash2(g**xy) shorthash("client", C, S, hexm, hexmu, hexsigma, hexHi, digest); enc64(kc, sizeof kc, digest, SHA1dlen); snprint(mess2, Maxmsg, "k'=%s\n", kc); conn->write(conn, (uchar*)mess2, strlen(mess2)); // set session key shorthash("session", C, S, hexm, hexmu, hexsigma, hexHi, digest); memset(hexsigma, 0, strlen(hexsigma)); n = conn->secret(conn, digest, 0); memset(digest, 0, SHA1dlen); if(n < 0){//assert writerr(conn, "can't set secret"); goto done; } rc = 0; done: mpfree(x); mpfree(sigma); mpfree(mu); mpfree(m); mpfree(Hi); mpfree(H); free(hexsigma); free(hexHi); free(hexm); free(mess); return rc; } char* secstorefetch(char *addr, char *owner, char *password) { int fd; char *rv; char s[Maxmsg+1], bye[10]; SConn *conn; char *pass, *sta; sta = nil; conn = nil; rv = nil; if(password != nil && *password) pass = strdup(password); else pass = readcons("secstore password", nil, 1); if(pass==nil || strlen(pass)==0){ werrstr("cancel"); goto Out; } if((fd = secdial(addr)) < 0) goto Out; if((conn = newSConn(fd)) == nil) goto Out; if(PAKclient(conn, owner, pass, nil) < 0){ werrstr("password mistyped?"); goto Out; } if(readstr(conn, s) < 0) goto Out; if(strcmp(s, "STA") == 0){ sta = readcons("STA PIN+SecureID", nil, 1); if(sta==nil || strlen(sta)==0){ werrstr("cancel"); goto Out; } if(strlen(sta) >= sizeof s - 3){ werrstr("STA response too long"); goto Out; } strcpy(s+3, sta); conn->write(conn, (uchar*)s, strlen(s)); readstr(conn, s); } if(strcmp(s, "OK") !=0){ werrstr("%s", s); goto Out; } if((rv = getfile(conn, (uchar*)pass, strlen(pass))) == nil) goto Out; strcpy(bye, "BYE"); conn->write(conn, (uchar*)bye, 3); Out: if(conn) conn->free(conn); if(pass) free(pass); if(sta) free(sta); return rv; } drawterm-20170818/win32-386/000077500000000000000000000000001314554504700151035ustar00rootroot00000000000000drawterm-20170818/win32-386/Makefile000066400000000000000000000004431314554504700165440ustar00rootroot00000000000000ROOT=.. include ../Make.config LIB=../libmachdep.a OFILES=\ getcallerpc.$O\ md5block.$O\ sha1block.$O\ tas.$O default: $(LIB) $(LIB): $(OFILES) $(AR) r $(LIB) $(OFILES) $(RANLIB) $(LIB) %.$O: %.c $(CC) $(CFLAGS) $*.c %.$O: %.s $(AS) -o $*.$O $*.s %.s: %.spp cpp $*.spp >$*.s drawterm-20170818/win32-386/getcallerpc.c000066400000000000000000000001361314554504700175340ustar00rootroot00000000000000#include "u.h" #include "libc.h" uintptr getcallerpc(void *a) { return ((uintptr*)a)[-1]; } drawterm-20170818/win32-386/md5block.spp000066400000000000000000000146771314554504700173460ustar00rootroot00000000000000/* * rfc1321 requires that I include this. The code is new. The constants * all come from the rfc (hence the copyright). We trade a table for the * macros in rfc. The total size is a lot less. -- presotto * * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it * is identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided * that such works are identified as "derived from the RSA Data * Security, Inc. MD5 Message-Digest Algorithm" in all material * mentioning or referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software forany particular purpose. It is provided "as is" * without express or implied warranty of any kind. * These notices must be retained in any copies of any part of this * documentation and/or software. */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 #define PAYME(x) $ ## x /* * SI is data * a += FN(B,C,D); * a += x[sh] + t[sh]; * a = (a << S11) | (a >> (32 - S11)); * a += b; */ #define BODY1(off,V,FN,SH,A,B,C,D)\ FN(B,C,D)\ leal V(A, %edi, 1), A;\ addl off(%ebp), A;\ roll PAYME(SH), A;\ addl B, A;\ #define BODY(off,V,FN,SH,A,B,C,D)\ FN(B,C,D)\ leal V(A, %edi, 1), A;\ addl (off)(%ebp), A;\ roll PAYME(SH), A;\ addl B,A;\ /* * fn1 = ((c ^ d) & b) ^ d */ #define FN1(B,C,D)\ movl C, %edi;\ xorl D, %edi;\ andl B, %edi;\ xorl D, %edi;\ /* * fn2 = ((b ^ c) & d) ^ c; */ #define FN2(B,C,D)\ movl B, %edi;\ xorl C, %edi;\ andl D, %edi;\ xorl C, %edi;\ /* * fn3 = b ^ c ^ d; */ #define FN3(B,C,D)\ movl B, %edi;\ xorl C, %edi;\ xorl D, %edi;\ /* * fn4 = c ^ (b | ~d); */ #define FN4(B,C,D)\ movl D, %edi;\ xorl $-1, %edi;\ orl B, %edi;\ xorl C, %edi;\ #define STACKSIZE 20 #define DATA (STACKSIZE+8) #define LEN (STACKSIZE+12) #define STATE (STACKSIZE+16) #define EDATA (STACKSIZE-4) #define OLDEBX (STACKSIZE-8) #define OLDESI (STACKSIZE-12) #define OLDEDI (STACKSIZE-16) .text .p2align 2,0x90 .globl ___md5block ___md5block: .p2align 2,0x90 .globl __md5block __md5block: .p2align 2,0x90 .globl _md5block _md5block: .p2align 2,0x90 .globl md5block md5block: /* Prelude */ pushl %ebp subl $(STACKSIZE), %esp movl %ebx, OLDEBX(%esp) movl %esi, OLDESI(%esp) movl %edi, OLDEDI(%esp) movl DATA(%esp), %eax addl LEN(%esp), %eax movl %eax, EDATA(%esp) movl DATA(%esp), %ebp 0: movl STATE(%esp), %esi movl (%esi), %eax movl 4(%esi), %ebx movl 8(%esi), %ecx movl 12(%esi), %edx BODY1( 0*4,0xd76aa478,FN1,S11,%eax,%ebx,%ecx,%edx) BODY1( 1*4,0xe8c7b756,FN1,S12,%edx,%eax,%ebx,%ecx) BODY1( 2*4,0x242070db,FN1,S13,%ecx,%edx,%eax,%ebx) BODY1( 3*4,0xc1bdceee,FN1,S14,%ebx,%ecx,%edx,%eax) BODY1( 4*4,0xf57c0faf,FN1,S11,%eax,%ebx,%ecx,%edx) BODY1( 5*4,0x4787c62a,FN1,S12,%edx,%eax,%ebx,%ecx) BODY1( 6*4,0xa8304613,FN1,S13,%ecx,%edx,%eax,%ebx) BODY1( 7*4,0xfd469501,FN1,S14,%ebx,%ecx,%edx,%eax) BODY1( 8*4,0x698098d8,FN1,S11,%eax,%ebx,%ecx,%edx) BODY1( 9*4,0x8b44f7af,FN1,S12,%edx,%eax,%ebx,%ecx) BODY1(10*4,0xffff5bb1,FN1,S13,%ecx,%edx,%eax,%ebx) BODY1(11*4,0x895cd7be,FN1,S14,%ebx,%ecx,%edx,%eax) BODY1(12*4,0x6b901122,FN1,S11,%eax,%ebx,%ecx,%edx) BODY1(13*4,0xfd987193,FN1,S12,%edx,%eax,%ebx,%ecx) BODY1(14*4,0xa679438e,FN1,S13,%ecx,%edx,%eax,%ebx) BODY1(15*4,0x49b40821,FN1,S14,%ebx,%ecx,%edx,%eax) BODY( 1*4,0xf61e2562,FN2,S21,%eax,%ebx,%ecx,%edx) BODY( 6*4,0xc040b340,FN2,S22,%edx,%eax,%ebx,%ecx) BODY(11*4,0x265e5a51,FN2,S23,%ecx,%edx,%eax,%ebx) BODY( 0*4,0xe9b6c7aa,FN2,S24,%ebx,%ecx,%edx,%eax) BODY( 5*4,0xd62f105d,FN2,S21,%eax,%ebx,%ecx,%edx) BODY(10*4,0x02441453,FN2,S22,%edx,%eax,%ebx,%ecx) BODY(15*4,0xd8a1e681,FN2,S23,%ecx,%edx,%eax,%ebx) BODY( 4*4,0xe7d3fbc8,FN2,S24,%ebx,%ecx,%edx,%eax) BODY( 9*4,0x21e1cde6,FN2,S21,%eax,%ebx,%ecx,%edx) BODY(14*4,0xc33707d6,FN2,S22,%edx,%eax,%ebx,%ecx) BODY( 3*4,0xf4d50d87,FN2,S23,%ecx,%edx,%eax,%ebx) BODY( 8*4,0x455a14ed,FN2,S24,%ebx,%ecx,%edx,%eax) BODY(13*4,0xa9e3e905,FN2,S21,%eax,%ebx,%ecx,%edx) BODY( 2*4,0xfcefa3f8,FN2,S22,%edx,%eax,%ebx,%ecx) BODY( 7*4,0x676f02d9,FN2,S23,%ecx,%edx,%eax,%ebx) BODY(12*4,0x8d2a4c8a,FN2,S24,%ebx,%ecx,%edx,%eax) BODY( 5*4,0xfffa3942,FN3,S31,%eax,%ebx,%ecx,%edx) BODY( 8*4,0x8771f681,FN3,S32,%edx,%eax,%ebx,%ecx) BODY(11*4,0x6d9d6122,FN3,S33,%ecx,%edx,%eax,%ebx) BODY(14*4,0xfde5380c,FN3,S34,%ebx,%ecx,%edx,%eax) BODY( 1*4,0xa4beea44,FN3,S31,%eax,%ebx,%ecx,%edx) BODY( 4*4,0x4bdecfa9,FN3,S32,%edx,%eax,%ebx,%ecx) BODY( 7*4,0xf6bb4b60,FN3,S33,%ecx,%edx,%eax,%ebx) BODY(10*4,0xbebfbc70,FN3,S34,%ebx,%ecx,%edx,%eax) BODY(13*4,0x289b7ec6,FN3,S31,%eax,%ebx,%ecx,%edx) BODY( 0*4,0xeaa127fa,FN3,S32,%edx,%eax,%ebx,%ecx) BODY( 3*4,0xd4ef3085,FN3,S33,%ecx,%edx,%eax,%ebx) BODY( 6*4,0x04881d05,FN3,S34,%ebx,%ecx,%edx,%eax) BODY( 9*4,0xd9d4d039,FN3,S31,%eax,%ebx,%ecx,%edx) BODY(12*4,0xe6db99e5,FN3,S32,%edx,%eax,%ebx,%ecx) BODY(15*4,0x1fa27cf8,FN3,S33,%ecx,%edx,%eax,%ebx) BODY( 2*4,0xc4ac5665,FN3,S34,%ebx,%ecx,%edx,%eax) BODY( 0*4,0xf4292244,FN4,S41,%eax,%ebx,%ecx,%edx) BODY( 7*4,0x432aff97,FN4,S42,%edx,%eax,%ebx,%ecx) BODY(14*4,0xab9423a7,FN4,S43,%ecx,%edx,%eax,%ebx) BODY( 5*4,0xfc93a039,FN4,S44,%ebx,%ecx,%edx,%eax) BODY(12*4,0x655b59c3,FN4,S41,%eax,%ebx,%ecx,%edx) BODY( 3*4,0x8f0ccc92,FN4,S42,%edx,%eax,%ebx,%ecx) BODY(10*4,0xffeff47d,FN4,S43,%ecx,%edx,%eax,%ebx) BODY( 1*4,0x85845dd1,FN4,S44,%ebx,%ecx,%edx,%eax) BODY( 8*4,0x6fa87e4f,FN4,S41,%eax,%ebx,%ecx,%edx) BODY(15*4,0xfe2ce6e0,FN4,S42,%edx,%eax,%ebx,%ecx) BODY( 6*4,0xa3014314,FN4,S43,%ecx,%edx,%eax,%ebx) BODY(13*4,0x4e0811a1,FN4,S44,%ebx,%ecx,%edx,%eax) BODY( 4*4,0xf7537e82,FN4,S41,%eax,%ebx,%ecx,%edx) BODY(11*4,0xbd3af235,FN4,S42,%edx,%eax,%ebx,%ecx) BODY( 2*4,0x2ad7d2bb,FN4,S43,%ecx,%edx,%eax,%ebx) BODY( 9*4,0xeb86d391,FN4,S44,%ebx,%ecx,%edx,%eax) addl $(16*4), %ebp movl STATE(%esp), %edi addl %eax,0(%edi) addl %ebx,4(%edi) addl %ecx,8(%edi) addl %edx,12(%edi) movl EDATA(%esp), %edi cmpl %edi, %ebp jb 0b /* Postlude */ movl OLDEBX(%esp), %ebx movl OLDESI(%esp), %esi movl OLDEDI(%esp), %edi addl $(STACKSIZE), %esp popl %ebp ret drawterm-20170818/win32-386/sha1block.spp000066400000000000000000000114601314554504700175000ustar00rootroot00000000000000.text .p2align 2,0x90 .globl ___sha1block ___sha1block: jmp sha1block .p2align 2,0x90 .globl __sha1block __sha1block: jmp sha1block .p2align 2,0x90 .globl _sha1block _sha1block: jmp sha1block .p2align 2,0x90 .globl sha1block sha1block: /* x = (wp[off-f] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1; * wp[off] = x; * x += A <<< 5; * E += 0xca62c1d6 + x; * x = FN(B,C,D); * E += x; * B >>> 2 */ #define BSWAPDI BYTE $0x0f; BYTE $0xcf; #define BODY(off,FN,V,A,B,C,D,E)\ movl (off-64)(%ebp), %edi;\ xorl (off-56)(%ebp), %edi;\ xorl (off-32)(%ebp), %edi;\ xorl (off-12)(%ebp), %edi;\ roll $1, %edi;\ movl %edi, off(%ebp);\ leal V(%edi, E, 1), E;\ movl A, %edi;\ roll $5, %edi;\ addl %edi, E;\ FN(B,C,D)\ addl %edi, E;\ rorl $2, B;\ #define BODY0(off,FN,V,A,B,C,D,E)\ movl off(%ebx), %edi;\ bswap %edi;\ movl %edi, off(%ebp);\ leal V(%edi,E,1), E;\ movl A, %edi;\ roll $5,%edi;\ addl %edi,E;\ FN(B,C,D)\ addl %edi,E;\ rorl $2,B;\ /* * fn1 = (((C^D)&B)^D); */ #define FN1(B,C,D)\ movl C, %edi;\ xorl D, %edi;\ andl B, %edi;\ xorl D, %edi;\ /* * fn24 = B ^ C ^ D */ #define FN24(B,C,D)\ movl B, %edi;\ xorl C, %edi;\ xorl D, %edi;\ /* * fn3 = ((B ^ C) & (D ^= B)) ^ B * D ^= B to restore D */ #define FN3(B,C,D)\ movl B, %edi;\ xorl C, %edi;\ xorl B, D;\ andl D, %edi;\ xorl B, %edi;\ xorl B, D;\ /* * stack offsets * void sha1block(uchar *DATA, int LEN, ulong *STATE) */ #define STACKSIZE (48+80*4) #define DATA (STACKSIZE+8) #define LEN (STACKSIZE+12) #define STATE (STACKSIZE+16) /* * stack offsets for locals * ulong w[80]; * uchar *edata; * ulong *w15, *w40, *w60, *w80; * register local * ulong *wp = %ebp * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi * ulong tmp = edi */ #define WARRAY (STACKSIZE-4-(80*4)) #define TMP1 (STACKSIZE-8-(80*4)) #define TMP2 (STACKSIZE-12-(80*4)) #define W15 (STACKSIZE-16-(80*4)) #define W40 (STACKSIZE-20-(80*4)) #define W60 (STACKSIZE-24-(80*4)) #define W80 (STACKSIZE-28-(80*4)) #define EDATA (STACKSIZE-32-(80*4)) #define OLDEBX (STACKSIZE-36-(80*4)) #define OLDESI (STACKSIZE-40-(80*4)) #define OLDEDI (STACKSIZE-44-(80*4)) /* Prelude */ pushl %ebp subl $(STACKSIZE), %esp mov %ebx, OLDEBX(%esp) mov %esi, OLDESI(%esp) mov %edi, OLDEDI(%esp) movl DATA(%esp), %eax addl LEN(%esp), %eax movl %eax, EDATA(%esp) leal (WARRAY+15*4)(%esp), %edi /* aw15 */ movl %edi, W15(%esp) leal (WARRAY+40*4)(%esp), %edx /* aw40 */ movl %edx, W40(%esp) leal (WARRAY+60*4)(%esp), %ecx /* aw60 */ movl %ecx, W60(%esp) leal (WARRAY+80*4)(%esp), %edi /* aw80 */ movl %edi, W80(%esp) 0: leal WARRAY(%esp), %ebp /* warray */ movl STATE(%esp), %edi /* state */ movl (%edi),%eax movl 4(%edi),%ebx movl %ebx, TMP1(%esp) /* tmp1 */ movl 8(%edi), %ecx movl 12(%edi), %edx movl 16(%edi), %esi movl DATA(%esp), %ebx /* data */ 1: BODY0(0,FN1,0x5a827999,%eax,TMP1(%esp),%ecx,%edx,%esi) movl %esi,TMP2(%esp) BODY0(4,FN1,0x5a827999,%esi,%eax,TMP1(%esp),%ecx,%edx) movl TMP1(%esp),%esi BODY0(8,FN1,0x5a827999,%edx,TMP2(%esp),%eax,%esi,%ecx) BODY0(12,FN1,0x5a827999,%ecx,%edx,TMP2(%esp),%eax,%esi) movl %esi,TMP1(%esp) BODY0(16,FN1,0x5a827999,%esi,%ecx,%edx,TMP2(%esp),%eax) movl TMP2(%esp),%esi addl $20, %ebx addl $20, %ebp cmpl W15(%esp), %ebp /* w15 */ jb 1b BODY0(0,FN1,0x5a827999,%eax,TMP1(%esp),%ecx,%edx,%esi) addl $4, %ebx MOVL %ebx, DATA(%esp) /* data */ MOVL TMP1(%esp),%ebx BODY(4,FN1,0x5a827999,%esi,%eax,%ebx,%ecx,%edx) BODY(8,FN1,0x5a827999,%edx,%esi,%eax,%ebx,%ecx) BODY(12,FN1,0x5a827999,%ecx,%edx,%esi,%eax,%ebx) BODY(16,FN1,0x5a827999,%ebx,%ecx,%edx,%esi,%eax) addl $20, %ebp 2: BODY(0,FN24,0x6ed9eba1,%eax,%ebx,%ecx,%edx,%esi) BODY(4,FN24,0x6ed9eba1,%esi,%eax,%ebx,%ecx,%edx) BODY(8,FN24,0x6ed9eba1,%edx,%esi,%eax,%ebx,%ecx) BODY(12,FN24,0x6ed9eba1,%ecx,%edx,%esi,%eax,%ebx) BODY(16,FN24,0x6ed9eba1,%ebx,%ecx,%edx,%esi,%eax) addl $20,%ebp cmpl W40(%esp), %ebp jb 2b 3: BODY(0,FN3,0x8f1bbcdc,%eax,%ebx,%ecx,%edx,%esi) BODY(4,FN3,0x8f1bbcdc,%esi,%eax,%ebx,%ecx,%edx) BODY(8,FN3,0x8f1bbcdc,%edx,%esi,%eax,%ebx,%ecx) BODY(12,FN3,0x8f1bbcdc,%ecx,%edx,%esi,%eax,%ebx) BODY(16,FN3,0x8f1bbcdc,%ebx,%ecx,%edx,%esi,%eax) addl $20, %ebp cmpl W60(%esp), %ebp /* w60 */ jb 3b 4: BODY(0,FN24,0xca62c1d6,%eax,%ebx,%ecx,%edx,%esi) BODY(4,FN24,0xca62c1d6,%esi,%eax,%ebx,%ecx,%edx) BODY(8,FN24,0xca62c1d6,%edx,%esi,%eax,%ebx,%ecx) BODY(12,FN24,0xca62c1d6,%ecx,%edx,%esi,%eax,%ebx) BODY(16,FN24,0xca62c1d6,%ebx,%ecx,%edx,%esi,%eax) addl $20, %ebp cmpl W80(%esp), %ebp /* w80 */ jb 4b movl STATE(%esp), %edi /* state */ addl %eax, 0(%edi) addl %ebx, 4(%edi) addl %ecx, 8(%edi) addl %edx, 12(%edi) addl %esi, 16(%edi) movl EDATA(%esp), %edi /* edata */ cmpl %edi, DATA(%esp) /* data */ jb 0b /* Postlude */ mov OLDEBX(%esp), %ebx mov OLDESI(%esp), %esi mov OLDEDI(%esp), %edi addl $(STACKSIZE), %esp popl %ebp ret drawterm-20170818/win32-386/tas.c000066400000000000000000000004161314554504700160370ustar00rootroot00000000000000#include "u.h" #include "libc.h" int tas(long *x) { int v; __asm__( "movl $1, %%eax\n\t" "xchgl %%eax,(%%ecx)" : "=a" (v) : "c" (x) ); switch(v) { case 0: case 1: return v; default: print("canlock: corrupted 0x%lux\n", v); return 1; } } drawterm-20170818/win32-factotum.c000066400000000000000000000003561314554504700165550ustar00rootroot00000000000000#include #include #include #include #include #include #include "drawterm.h" #undef getenv char* getuser(void) { return getenv("USER"); } int dialfactotum(void) { return -1; }