terminal.c 294 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136
  1. /*
  2. * Terminal emulator.
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <ctype.h>
  7. #include <limits.h>
  8. #include <wchar.h>
  9. #include <time.h>
  10. #include <assert.h>
  11. #include "putty.h"
  12. #include "terminal.h"
  13. #define VT52_PLUS
  14. #define CL_ANSIMIN 0x0001 /* Codes in all ANSI like terminals. */
  15. #define CL_VT100 0x0002 /* VT100 */
  16. #define CL_VT100AVO 0x0004 /* VT100 +AVO; 132x24 (not 132x14) & attrs */
  17. #define CL_VT102 0x0008 /* VT102 */
  18. #define CL_VT220 0x0010 /* VT220 */
  19. #define CL_VT320 0x0020 /* VT320 */
  20. #define CL_VT420 0x0040 /* VT420 */
  21. #define CL_VT510 0x0080 /* VT510, NB VT510 includes ANSI */
  22. #define CL_VT340TEXT 0x0100 /* VT340 extensions that appear in the VT420 */
  23. #define CL_SCOANSI 0x1000 /* SCOANSI not in ANSIMIN. */
  24. #define CL_ANSI 0x2000 /* ANSI ECMA-48 not in the VT100..VT420 */
  25. #define CL_OTHER 0x4000 /* Others, Xterm, linux, putty, dunno, etc */
  26. #define TM_VT100 (CL_ANSIMIN|CL_VT100)
  27. #define TM_VT100AVO (TM_VT100|CL_VT100AVO)
  28. #define TM_VT102 (TM_VT100AVO|CL_VT102)
  29. #define TM_VT220 (TM_VT102|CL_VT220)
  30. #define TM_VTXXX (TM_VT220|CL_VT340TEXT|CL_VT510|CL_VT420|CL_VT320)
  31. #define TM_SCOANSI (CL_ANSIMIN|CL_SCOANSI)
  32. #define TM_PUTTY (0xFFFF)
  33. #define UPDATE_DELAY ((TICKSPERSEC+49)/50)/* ticks to defer window update */
  34. #define TBLINK_DELAY ((TICKSPERSEC*9+19)/20)/* ticks between text blinks*/
  35. #define CBLINK_DELAY (CURSORBLINK) /* ticks between cursor blinks */
  36. #define VBELL_DELAY (VBELL_TIMEOUT) /* visual bell timeout in ticks */
  37. #define compatibility(x) \
  38. if ( ((CL_##x)&term->compatibility_level) == 0 ) { \
  39. term->termstate=TOPLEVEL; \
  40. break; \
  41. }
  42. #define compatibility2(x,y) \
  43. if ( ((CL_##x|CL_##y)&term->compatibility_level) == 0 ) { \
  44. term->termstate=TOPLEVEL; \
  45. break; \
  46. }
  47. #define has_compat(x) ( ((CL_##x)&term->compatibility_level) != 0 )
  48. static const char *const EMPTY_WINDOW_TITLE = "";
  49. static const char sco2ansicolour[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
  50. #define sel_nl_sz (sizeof(sel_nl)/sizeof(wchar_t))
  51. static const wchar_t sel_nl[] = SEL_NL;
  52. /* forward declaration */
  53. static void term_userpass_state_free(struct term_userpass_state *s);
  54. /*
  55. * Fetch the character at a particular position in a line array,
  56. * for purposes of `wordtype'. The reason this isn't just a simple
  57. * array reference is that if the character we find is UCSWIDE,
  58. * then we must look one space further to the left.
  59. */
  60. #define UCSGET(a, x) \
  61. ( (x)>0 && (a)[(x)].chr == UCSWIDE ? (a)[(x)-1].chr : (a)[(x)].chr )
  62. /*
  63. * Detect the various aliases of U+0020 SPACE.
  64. */
  65. #define IS_SPACE_CHR(chr) \
  66. ((chr) == 0x20 || (DIRECT_CHAR(chr) && ((chr) & 0xFF) == 0x20))
  67. /*
  68. * Spot magic CSETs.
  69. */
  70. #define CSET_OF(chr) (DIRECT_CHAR(chr)||DIRECT_FONT(chr) ? (chr)&CSET_MASK : 0)
  71. /*
  72. * Internal prototypes.
  73. */
  74. static void resizeline(Terminal *, termline *, int);
  75. static termline *lineptr(Terminal *, int, int);
  76. static void check_line_size(Terminal *, termline *);
  77. static void do_paint(Terminal *);
  78. static void erase_lots(Terminal *, bool, bool, bool);
  79. static int find_last_nonempty_line(Terminal *, tree234 *);
  80. static void swap_screen(Terminal *, int, bool, bool);
  81. static void update_sbar(Terminal *);
  82. static void deselect(Terminal *);
  83. static void term_print_finish(Terminal *);
  84. static void scroll(Terminal *, int, int, int, bool);
  85. static void parse_optionalrgb(optionalrgb *out, unsigned *values);
  86. static void term_added_data(Terminal *term, bool);
  87. static void term_update_raw_mouse_mode(Terminal *term);
  88. static void term_out_cb(void *);
  89. static termline *newtermline(Terminal *term, int cols, bool bce)
  90. {
  91. termline *line;
  92. int j;
  93. line = snew(termline);
  94. line->chars = snewn(cols, termchar);
  95. for (j = 0; j < cols; j++)
  96. line->chars[j] = (bce ? term->erase_char : term->basic_erase_char);
  97. line->cols = line->size = cols;
  98. line->lattr = LATTR_NORM;
  99. line->trusted = false;
  100. line->temporary = false;
  101. line->cc_free = 0;
  102. return line;
  103. }
  104. static void freetermline(termline *line)
  105. {
  106. if (line) {
  107. sfree(line->chars);
  108. sfree(line);
  109. }
  110. }
  111. void term_release_line(termline *line)
  112. {
  113. if (line->temporary)
  114. freetermline(line);
  115. }
  116. const int colour_indices_conf_to_oscp[CONF_NCOLOURS] = {
  117. #define COLOUR_ENTRY(id,name) OSCP_COLOUR_##id,
  118. CONF_COLOUR_LIST(COLOUR_ENTRY)
  119. #undef COLOUR_ENTRY
  120. };
  121. const int colour_indices_conf_to_osc4[CONF_NCOLOURS] = {
  122. #define COLOUR_ENTRY(id,name) OSC4_COLOUR_##id,
  123. CONF_COLOUR_LIST(COLOUR_ENTRY)
  124. #undef COLOUR_ENTRY
  125. };
  126. const int colour_indices_oscp_to_osc4[OSCP_NCOLOURS] = {
  127. #define COLOUR_ENTRY(id) OSC4_COLOUR_##id,
  128. OSCP_COLOUR_LIST(COLOUR_ENTRY)
  129. #undef COLOUR_ENTRY
  130. };
  131. #ifdef TERM_CC_DIAGS
  132. /*
  133. * Diagnostic function: verify that a termline has a correct
  134. * combining character structure.
  135. *
  136. * This is a performance-intensive check, so it's no longer enabled
  137. * by default.
  138. */
  139. static void cc_check(termline *line)
  140. {
  141. unsigned char *flags;
  142. int i, j;
  143. assert(line->size >= line->cols);
  144. flags = snewn(line->size, unsigned char);
  145. for (i = 0; i < line->size; i++)
  146. flags[i] = (i < line->cols);
  147. for (i = 0; i < line->cols; i++) {
  148. j = i;
  149. while (line->chars[j].cc_next) {
  150. j += line->chars[j].cc_next;
  151. assert(j >= line->cols && j < line->size);
  152. assert(!flags[j]);
  153. flags[j] = true;
  154. }
  155. }
  156. j = line->cc_free;
  157. if (j) {
  158. while (1) {
  159. assert(j >= line->cols && j < line->size);
  160. assert(!flags[j]);
  161. flags[j] = true;
  162. if (line->chars[j].cc_next)
  163. j += line->chars[j].cc_next;
  164. else
  165. break;
  166. }
  167. }
  168. j = 0;
  169. for (i = 0; i < line->size; i++)
  170. j += (flags[i] != 0);
  171. assert(j == line->size);
  172. sfree(flags);
  173. }
  174. #endif
  175. static void clear_cc(termline *line, int col);
  176. /*
  177. * Add a combining character to a character cell.
  178. */
  179. static void add_cc(termline *line, int col, unsigned long chr)
  180. {
  181. int newcc;
  182. assert(col >= 0 && col < line->cols);
  183. /*
  184. * Don't add combining characters at all to U+FFFD REPLACEMENT
  185. * CHARACTER. (Partly it's a slightly incoherent idea in the first
  186. * place; mostly, U+FFFD is what we generate if a cell already has
  187. * too many ccs, in which case we want it to be a fixed point when
  188. * further ccs are added.)
  189. */
  190. if (line->chars[col].chr == 0xFFFD)
  191. return;
  192. /*
  193. * Walk the cc list of the cell in question to find its current
  194. * end point.
  195. */
  196. size_t ncc = 0;
  197. int origcol = col;
  198. while (line->chars[col].cc_next) {
  199. col += line->chars[col].cc_next;
  200. if (++ncc >= CC_LIMIT) {
  201. /*
  202. * There are already too many combining characters in this
  203. * character cell. Change strategy: throw out the entire
  204. * chain and replace the main character with U+FFFD.
  205. *
  206. * (Rationale: extrapolating from UTR #36 section 3.6.2
  207. * suggests the principle that it's better to substitute
  208. * U+FFFD than to _ignore_ input completely. Also, if the
  209. * user copies and pastes an overcombined character cell,
  210. * this way it will clearly indicate that we haven't
  211. * reproduced the writer's original intentions, instead of
  212. * looking as if it was the _writer's_ fault that the 33rd
  213. * cc is missing.)
  214. *
  215. * Per the code above, this will also prevent any further
  216. * ccs from being added to this cell.
  217. */
  218. clear_cc(line, origcol);
  219. line->chars[origcol].chr = 0xFFFD;
  220. return;
  221. }
  222. }
  223. /*
  224. * Extend the cols array if the free list is empty.
  225. */
  226. if (!line->cc_free) {
  227. int n = line->size;
  228. size_t tmpsize = line->size;
  229. sgrowarray(line->chars, tmpsize, tmpsize);
  230. assert(tmpsize <= INT_MAX);
  231. line->size = tmpsize;
  232. line->cc_free = n;
  233. while (n < line->size) {
  234. if (n+1 < line->size)
  235. line->chars[n].cc_next = 1;
  236. else
  237. line->chars[n].cc_next = 0;
  238. n++;
  239. }
  240. }
  241. /*
  242. * `col' now points at the last cc currently in this cell; so
  243. * we simply add another one.
  244. */
  245. newcc = line->cc_free;
  246. if (line->chars[newcc].cc_next)
  247. line->cc_free = newcc + line->chars[newcc].cc_next;
  248. else
  249. line->cc_free = 0;
  250. line->chars[newcc].cc_next = 0;
  251. line->chars[newcc].chr = chr;
  252. line->chars[col].cc_next = newcc - col;
  253. #ifdef TERM_CC_DIAGS
  254. cc_check(line);
  255. #endif
  256. }
  257. /*
  258. * Clear the combining character list in a character cell.
  259. */
  260. static void clear_cc(termline *line, int col)
  261. {
  262. int oldfree, origcol = col;
  263. assert(col >= 0 && col < line->cols);
  264. if (!line->chars[col].cc_next)
  265. return; /* nothing needs doing */
  266. oldfree = line->cc_free;
  267. line->cc_free = col + line->chars[col].cc_next;
  268. while (line->chars[col].cc_next)
  269. col += line->chars[col].cc_next;
  270. if (oldfree)
  271. line->chars[col].cc_next = oldfree - col;
  272. else
  273. line->chars[col].cc_next = 0;
  274. line->chars[origcol].cc_next = 0;
  275. #ifdef TERM_CC_DIAGS
  276. cc_check(line);
  277. #endif
  278. }
  279. /*
  280. * Compare two character cells for equality. Special case required
  281. * in do_paint() where we override what we expect the chr and attr
  282. * fields to be.
  283. */
  284. static bool termchars_equal_override(termchar *a, termchar *b,
  285. unsigned long bchr, unsigned long battr)
  286. {
  287. /* FULL-TERMCHAR */
  288. if (!truecolour_equal(a->truecolour, b->truecolour))
  289. return false;
  290. if (a->chr != bchr)
  291. return false;
  292. if ((a->attr &~ DATTR_MASK) != (battr &~ DATTR_MASK))
  293. return false;
  294. while (a->cc_next || b->cc_next) {
  295. if (!a->cc_next || !b->cc_next)
  296. return false; /* one cc-list ends, other does not */
  297. a += a->cc_next;
  298. b += b->cc_next;
  299. if (a->chr != b->chr)
  300. return false;
  301. }
  302. return true;
  303. }
  304. static bool termchars_equal(termchar *a, termchar *b)
  305. {
  306. return termchars_equal_override(a, b, b->chr, b->attr);
  307. }
  308. /*
  309. * Copy a character cell. (Requires a pointer to the destination
  310. * termline, so as to access its free list.)
  311. */
  312. static void copy_termchar(termline *destline, int x, termchar *src)
  313. {
  314. clear_cc(destline, x);
  315. destline->chars[x] = *src; /* copy everything except cc-list */
  316. destline->chars[x].cc_next = 0; /* and make sure this is zero */
  317. while (src->cc_next) {
  318. src += src->cc_next;
  319. add_cc(destline, x, src->chr);
  320. }
  321. #ifdef TERM_CC_DIAGS
  322. cc_check(destline);
  323. #endif
  324. }
  325. /*
  326. * Move a character cell within its termline.
  327. */
  328. static void move_termchar(termline *line, termchar *dest, termchar *src)
  329. {
  330. /* First clear the cc list from the original char, just in case. */
  331. clear_cc(line, dest - line->chars);
  332. /* Move the character cell and adjust its cc_next. */
  333. *dest = *src; /* copy everything except cc-list */
  334. if (src->cc_next)
  335. dest->cc_next = src->cc_next - (dest-src);
  336. /* Ensure the original cell doesn't have a cc list. */
  337. src->cc_next = 0;
  338. #ifdef TERM_CC_DIAGS
  339. cc_check(line);
  340. #endif
  341. }
  342. #ifndef NO_SCROLLBACK_COMPRESSION
  343. /*
  344. * Compress and decompress a termline into an RLE-based format for
  345. * storing in scrollback. (Since scrollback almost never needs to
  346. * be modified and exists in huge quantities, this is a sensible
  347. * tradeoff, particularly since it allows us to continue adding
  348. * features to the main termchar structure without proportionally
  349. * bloating the terminal emulator's memory footprint unless those
  350. * features are in constant use.)
  351. */
  352. static void makerle(strbuf *b, termline *ldata,
  353. void (*makeliteral)(strbuf *b, termchar *c,
  354. unsigned long *state))
  355. {
  356. int hdrpos, hdrsize, n, prevlen, prevpos, thislen, thispos;
  357. bool prev2;
  358. termchar *c = ldata->chars;
  359. unsigned long state = 0, oldstate;
  360. n = ldata->cols;
  361. hdrpos = b->len;
  362. hdrsize = 0;
  363. put_byte(b, 0);
  364. prevlen = prevpos = 0;
  365. prev2 = false;
  366. while (n-- > 0) {
  367. thispos = b->len;
  368. makeliteral(b, c++, &state);
  369. thislen = b->len - thispos;
  370. if (thislen == prevlen &&
  371. !memcmp(b->u + prevpos, b->u + thispos, thislen)) {
  372. /*
  373. * This literal precisely matches the previous one.
  374. * Turn it into a run if it's worthwhile.
  375. *
  376. * With one-byte literals, it costs us two bytes to
  377. * encode a run, plus another byte to write the header
  378. * to resume normal output; so a three-element run is
  379. * neutral, and anything beyond that is unconditionally
  380. * worthwhile. With two-byte literals or more, even a
  381. * 2-run is a win.
  382. */
  383. if (thislen > 1 || prev2) {
  384. int runpos, runlen;
  385. /*
  386. * It's worth encoding a run. Start at prevpos,
  387. * unless hdrsize==0 in which case we can back up
  388. * another one and start by overwriting hdrpos.
  389. */
  390. hdrsize--; /* remove the literal at prevpos */
  391. if (prev2) {
  392. assert(hdrsize > 0);
  393. hdrsize--;
  394. prevpos -= prevlen;/* and possibly another one */
  395. }
  396. if (hdrsize == 0) {
  397. assert(prevpos == hdrpos + 1);
  398. runpos = hdrpos;
  399. strbuf_shrink_to(b, prevpos+prevlen);
  400. } else {
  401. memmove(b->u + prevpos+1, b->u + prevpos, prevlen);
  402. runpos = prevpos;
  403. strbuf_shrink_to(b, prevpos+prevlen+1);
  404. /*
  405. * Terminate the previous run of ordinary
  406. * literals.
  407. */
  408. assert(hdrsize >= 1 && hdrsize <= 128);
  409. b->u[hdrpos] = hdrsize - 1;
  410. }
  411. runlen = prev2 ? 3 : 2;
  412. while (n > 0 && runlen < 129) {
  413. int tmppos, tmplen;
  414. tmppos = b->len;
  415. oldstate = state;
  416. makeliteral(b, c, &state);
  417. tmplen = b->len - tmppos;
  418. bool match = tmplen == thislen &&
  419. !memcmp(b->u + runpos+1, b->u + tmppos, tmplen);
  420. strbuf_shrink_to(b, tmppos);
  421. if (!match) {
  422. state = oldstate;
  423. break; /* run over */
  424. }
  425. n--, c++, runlen++;
  426. }
  427. assert(runlen >= 2 && runlen <= 129);
  428. b->u[runpos] = runlen + 0x80 - 2;
  429. hdrpos = b->len;
  430. hdrsize = 0;
  431. put_byte(b, 0);
  432. /* And ensure this run doesn't interfere with the next. */
  433. prevlen = prevpos = 0;
  434. prev2 = false;
  435. continue;
  436. } else {
  437. /*
  438. * Just flag that the previous two literals were
  439. * identical, in case we find a third identical one
  440. * we want to turn into a run.
  441. */
  442. prev2 = true;
  443. prevlen = thislen;
  444. prevpos = thispos;
  445. }
  446. } else {
  447. prev2 = false;
  448. prevlen = thislen;
  449. prevpos = thispos;
  450. }
  451. /*
  452. * This character isn't (yet) part of a run. Add it to
  453. * hdrsize.
  454. */
  455. hdrsize++;
  456. if (hdrsize == 128) {
  457. b->u[hdrpos] = hdrsize - 1;
  458. hdrpos = b->len;
  459. hdrsize = 0;
  460. put_byte(b, 0);
  461. prevlen = prevpos = 0;
  462. prev2 = false;
  463. }
  464. }
  465. /*
  466. * Clean up.
  467. */
  468. if (hdrsize > 0) {
  469. assert(hdrsize <= 128);
  470. b->u[hdrpos] = hdrsize - 1;
  471. } else {
  472. strbuf_shrink_to(b, hdrpos);
  473. }
  474. }
  475. static void makeliteral_chr(strbuf *b, termchar *c, unsigned long *state)
  476. {
  477. /*
  478. * My encoding for characters is UTF-8-like, in that it stores
  479. * 7-bit ASCII in one byte and uses high-bit-set bytes as
  480. * introducers to indicate a longer sequence. However, it's
  481. * unlike UTF-8 in that it doesn't need to be able to
  482. * resynchronise, and therefore I don't want to waste two bits
  483. * per byte on having recognisable continuation characters.
  484. * Also I don't want to rule out the possibility that I may one
  485. * day use values 0x80000000-0xFFFFFFFF for interesting
  486. * purposes, so unlike UTF-8 I need a full 32-bit range.
  487. * Accordingly, here is my encoding:
  488. *
  489. * 00000000-0000007F: 0xxxxxxx (but see below)
  490. * 00000080-00003FFF: 10xxxxxx xxxxxxxx
  491. * 00004000-001FFFFF: 110xxxxx xxxxxxxx xxxxxxxx
  492. * 00200000-0FFFFFFF: 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx
  493. * 10000000-FFFFFFFF: 11110ZZZ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
  494. *
  495. * (`Z' is like `x' but is always going to be zero since the
  496. * values I'm encoding don't go above 2^32. In principle the
  497. * five-byte form of the encoding could extend to 2^35, and
  498. * there could be six-, seven-, eight- and nine-byte forms as
  499. * well to allow up to 64-bit values to be encoded. But that's
  500. * completely unnecessary for these purposes!)
  501. *
  502. * The encoding as written above would be very simple, except
  503. * that 7-bit ASCII can occur in several different ways in the
  504. * terminal data; sometimes it crops up in the D800 page
  505. * (CSET_ASCII) but at other times it's in the 0000 page (real
  506. * Unicode). Therefore, this encoding is actually _stateful_:
  507. * the one-byte encoding of 00-7F actually indicates `reuse the
  508. * upper three bytes of the last character', and to encode an
  509. * absolute value of 00-7F you need to use the two-byte form
  510. * instead.
  511. */
  512. if ((c->chr & ~0x7F) == *state) {
  513. put_byte(b, (unsigned char)(c->chr & 0x7F));
  514. } else if (c->chr < 0x4000) {
  515. put_byte(b, (unsigned char)(((c->chr >> 8) & 0x3F) | 0x80));
  516. put_byte(b, (unsigned char)(c->chr & 0xFF));
  517. } else if (c->chr < 0x200000) {
  518. put_byte(b, (unsigned char)(((c->chr >> 16) & 0x1F) | 0xC0));
  519. put_uint16(b, c->chr & 0xFFFF);
  520. } else if (c->chr < 0x10000000) {
  521. put_byte(b, (unsigned char)(((c->chr >> 24) & 0x0F) | 0xE0));
  522. put_byte(b, (unsigned char)((c->chr >> 16) & 0xFF));
  523. put_uint16(b, c->chr & 0xFFFF);
  524. } else {
  525. put_byte(b, 0xF0);
  526. put_uint32(b, c->chr);
  527. }
  528. *state = c->chr & ~0xFF;
  529. }
  530. static void makeliteral_attr(strbuf *b, termchar *c, unsigned long *state)
  531. {
  532. /*
  533. * My encoding for attributes is 16-bit-granular and assumes
  534. * that the top bit of the word is never required. I either
  535. * store a two-byte value with the top bit clear (indicating
  536. * just that value), or a four-byte value with the top bit set
  537. * (indicating the same value with its top bit clear).
  538. *
  539. * However, first I permute the bits of the attribute value, so
  540. * that the eight bits of colour (four in each of fg and bg)
  541. * which are never non-zero unless xterm 256-colour mode is in
  542. * use are placed higher up the word than everything else. This
  543. * ensures that attribute values remain 16-bit _unless_ the
  544. * user uses extended colour.
  545. */
  546. unsigned attr, colourbits;
  547. attr = c->attr;
  548. assert(ATTR_BGSHIFT > ATTR_FGSHIFT);
  549. colourbits = (attr >> (ATTR_BGSHIFT + 4)) & 0xF;
  550. colourbits <<= 4;
  551. colourbits |= (attr >> (ATTR_FGSHIFT + 4)) & 0xF;
  552. attr = (((attr >> (ATTR_BGSHIFT + 8)) << (ATTR_BGSHIFT + 4)) |
  553. (attr & ((1 << (ATTR_BGSHIFT + 4))-1)));
  554. attr = (((attr >> (ATTR_FGSHIFT + 8)) << (ATTR_FGSHIFT + 4)) |
  555. (attr & ((1 << (ATTR_FGSHIFT + 4))-1)));
  556. attr |= (colourbits << (32-9));
  557. if (attr < 0x8000) {
  558. put_byte(b, (unsigned char)((attr >> 8) & 0xFF));
  559. put_byte(b, (unsigned char)(attr & 0xFF));
  560. } else {
  561. put_byte(b, (unsigned char)(((attr >> 24) & 0x7F) | 0x80));
  562. put_byte(b, (unsigned char)((attr >> 16) & 0xFF));
  563. put_byte(b, (unsigned char)((attr >> 8) & 0xFF));
  564. put_byte(b, (unsigned char)(attr & 0xFF));
  565. }
  566. }
  567. static void makeliteral_truecolour(strbuf *b, termchar *c, unsigned long *state)
  568. {
  569. /*
  570. * Put the used parts of the colour info into the buffer.
  571. */
  572. put_byte(b, ((c->truecolour.fg.enabled ? 1 : 0) |
  573. (c->truecolour.bg.enabled ? 2 : 0)));
  574. if (c->truecolour.fg.enabled) {
  575. put_byte(b, c->truecolour.fg.r);
  576. put_byte(b, c->truecolour.fg.g);
  577. put_byte(b, c->truecolour.fg.b);
  578. }
  579. if (c->truecolour.bg.enabled) {
  580. put_byte(b, c->truecolour.bg.r);
  581. put_byte(b, c->truecolour.bg.g);
  582. put_byte(b, c->truecolour.bg.b);
  583. }
  584. }
  585. static void makeliteral_cc(strbuf *b, termchar *c, unsigned long *state)
  586. {
  587. /*
  588. * For combining characters, I just encode a bunch of ordinary
  589. * chars using makeliteral_chr, and terminate with a \0
  590. * character (which I know won't come up as a combining char
  591. * itself).
  592. *
  593. * I don't use the stateful encoding in makeliteral_chr.
  594. */
  595. unsigned long zstate;
  596. termchar z;
  597. while (c->cc_next) {
  598. c += c->cc_next;
  599. assert(c->chr != 0);
  600. zstate = 0;
  601. makeliteral_chr(b, c, &zstate);
  602. }
  603. z.chr = 0;
  604. zstate = 0;
  605. makeliteral_chr(b, &z, &zstate);
  606. }
  607. typedef struct compressed_scrollback_line {
  608. size_t len;
  609. /* compressed data follows after this */
  610. } compressed_scrollback_line;
  611. static termline *decompressline_no_free(compressed_scrollback_line *line);
  612. static compressed_scrollback_line *compressline_no_free(termline *ldata)
  613. {
  614. strbuf *b = strbuf_new();
  615. /* Leave space for the header structure */
  616. strbuf_append(b, sizeof(compressed_scrollback_line));
  617. /*
  618. * First, store the column count, 7 bits at a time, least
  619. * significant `digit' first, with the high bit set on all but
  620. * the last.
  621. */
  622. {
  623. int n = ldata->cols;
  624. while (n >= 128) {
  625. put_byte(b, (unsigned char)((n & 0x7F) | 0x80));
  626. n >>= 7;
  627. }
  628. put_byte(b, (unsigned char)(n));
  629. }
  630. /*
  631. * Next store the lattrs; same principle. We add one extra bit to
  632. * this to indicate the trust state of the line.
  633. */
  634. {
  635. int n = ldata->lattr | (ldata->trusted ? 0x10000 : 0);
  636. while (n >= 128) {
  637. put_byte(b, (unsigned char)((n & 0x7F) | 0x80));
  638. n >>= 7;
  639. }
  640. put_byte(b, (unsigned char)(n));
  641. }
  642. /*
  643. * Now we store a sequence of separate run-length encoded
  644. * fragments, each containing exactly as many symbols as there
  645. * are columns in the ldata.
  646. *
  647. * All of these have a common basic format:
  648. *
  649. * - a byte 00-7F indicates that X+1 literals follow it
  650. * - a byte 80-FF indicates that a single literal follows it
  651. * and expects to be repeated (X-0x80)+2 times.
  652. *
  653. * The format of the `literals' varies between the fragments.
  654. */
  655. makerle(b, ldata, makeliteral_chr);
  656. makerle(b, ldata, makeliteral_attr);
  657. makerle(b, ldata, makeliteral_truecolour);
  658. makerle(b, ldata, makeliteral_cc);
  659. size_t linelen = b->len - sizeof(compressed_scrollback_line);
  660. compressed_scrollback_line *line =
  661. (compressed_scrollback_line *)strbuf_to_str(b);
  662. line->len = linelen;
  663. /*
  664. * Diagnostics: ensure that the compressed data really does
  665. * decompress to the right thing.
  666. *
  667. * This is a bit performance-heavy for production code.
  668. */
  669. #ifdef TERM_CC_DIAGS
  670. #ifndef CHECK_SB_COMPRESSION
  671. {
  672. termline *dcl;
  673. int i;
  674. #ifdef DIAGNOSTIC_SB_COMPRESSION
  675. for (i = 0; i < b->len; i++) {
  676. printf(" %02x ", b->data[i]);
  677. }
  678. printf("\n");
  679. #endif
  680. dcl = decompressline_no_free(line);
  681. assert(ldata->cols == dcl->cols);
  682. assert(ldata->lattr == dcl->lattr);
  683. for (i = 0; i < ldata->cols; i++)
  684. assert(termchars_equal(&ldata->chars[i], &dcl->chars[i]));
  685. #ifdef DIAGNOSTIC_SB_COMPRESSION
  686. printf("%d cols (%d bytes) -> %d bytes (factor of %g)\n",
  687. ldata->cols, 4 * ldata->cols, dused,
  688. (double)dused / (4 * ldata->cols));
  689. #endif
  690. freetermline(dcl);
  691. }
  692. #endif
  693. #endif /* TERM_CC_DIAGS */
  694. return line;
  695. }
  696. static compressed_scrollback_line *compressline_and_free(termline *ldata)
  697. {
  698. compressed_scrollback_line *cline = compressline_no_free(ldata);
  699. freetermline(ldata);
  700. return cline;
  701. }
  702. static void readrle(BinarySource *bs, termline *ldata,
  703. void (*readliteral)(BinarySource *bs, termchar *c,
  704. termline *ldata, unsigned long *state))
  705. {
  706. int n = 0;
  707. unsigned long state = 0;
  708. while (n < ldata->cols) {
  709. int hdr = get_byte(bs);
  710. if (hdr >= 0x80) {
  711. /* A run. */
  712. size_t pos = bs->pos, count = hdr + 2 - 0x80;
  713. while (count--) {
  714. assert(n < ldata->cols);
  715. bs->pos = pos;
  716. readliteral(bs, ldata->chars + n, ldata, &state);
  717. n++;
  718. }
  719. } else {
  720. /* Just a sequence of consecutive literals. */
  721. int count = hdr + 1;
  722. while (count--) {
  723. assert(n < ldata->cols);
  724. readliteral(bs, ldata->chars + n, ldata, &state);
  725. n++;
  726. }
  727. }
  728. }
  729. assert(n == ldata->cols);
  730. }
  731. static void readliteral_chr(BinarySource *bs, termchar *c, termline *ldata,
  732. unsigned long *state)
  733. {
  734. int byte;
  735. /*
  736. * 00000000-0000007F: 0xxxxxxx
  737. * 00000080-00003FFF: 10xxxxxx xxxxxxxx
  738. * 00004000-001FFFFF: 110xxxxx xxxxxxxx xxxxxxxx
  739. * 00200000-0FFFFFFF: 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx
  740. * 10000000-FFFFFFFF: 11110ZZZ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
  741. */
  742. byte = get_byte(bs);
  743. if (byte < 0x80) {
  744. c->chr = byte | *state;
  745. } else if (byte < 0xC0) {
  746. c->chr = (byte &~ 0xC0) << 8;
  747. c->chr |= get_byte(bs);
  748. } else if (byte < 0xE0) {
  749. c->chr = (byte &~ 0xE0) << 16;
  750. c->chr |= get_uint16(bs);
  751. } else if (byte < 0xF0) {
  752. c->chr = (byte &~ 0xF0) << 24;
  753. c->chr |= get_byte(bs) << 16;
  754. c->chr |= get_uint16(bs);
  755. } else {
  756. assert(byte == 0xF0);
  757. c->chr = get_uint32(bs);
  758. }
  759. *state = c->chr & ~0xFF;
  760. }
  761. static void readliteral_attr(BinarySource *bs, termchar *c, termline *ldata,
  762. unsigned long *state)
  763. {
  764. unsigned val, attr, colourbits;
  765. val = get_uint16(bs);
  766. if (val >= 0x8000) {
  767. val &= ~0x8000;
  768. val <<= 16;
  769. val |= get_uint16(bs);
  770. }
  771. colourbits = (val >> (32-9)) & 0xFF;
  772. attr = (val & ((1<<(32-9))-1));
  773. attr = (((attr >> (ATTR_FGSHIFT + 4)) << (ATTR_FGSHIFT + 8)) |
  774. (attr & ((1 << (ATTR_FGSHIFT + 4))-1)));
  775. attr = (((attr >> (ATTR_BGSHIFT + 4)) << (ATTR_BGSHIFT + 8)) |
  776. (attr & ((1 << (ATTR_BGSHIFT + 4))-1)));
  777. attr |= (colourbits >> 4) << (ATTR_BGSHIFT + 4);
  778. attr |= (colourbits & 0xF) << (ATTR_FGSHIFT + 4);
  779. c->attr = attr;
  780. }
  781. static void readliteral_truecolour(
  782. BinarySource *bs, termchar *c, termline *ldata, unsigned long *state)
  783. {
  784. int flags = get_byte(bs);
  785. if (flags & 1) {
  786. c->truecolour.fg.enabled = true;
  787. c->truecolour.fg.r = get_byte(bs);
  788. c->truecolour.fg.g = get_byte(bs);
  789. c->truecolour.fg.b = get_byte(bs);
  790. } else {
  791. c->truecolour.fg = optionalrgb_none;
  792. }
  793. if (flags & 2) {
  794. c->truecolour.bg.enabled = true;
  795. c->truecolour.bg.r = get_byte(bs);
  796. c->truecolour.bg.g = get_byte(bs);
  797. c->truecolour.bg.b = get_byte(bs);
  798. } else {
  799. c->truecolour.bg = optionalrgb_none;
  800. }
  801. }
  802. static void readliteral_cc(BinarySource *bs, termchar *c, termline *ldata,
  803. unsigned long *state)
  804. {
  805. termchar n;
  806. unsigned long zstate;
  807. int x = c - ldata->chars;
  808. c->cc_next = 0;
  809. while (1) {
  810. zstate = 0;
  811. readliteral_chr(bs, &n, ldata, &zstate);
  812. if (!n.chr)
  813. break;
  814. add_cc(ldata, x, n.chr);
  815. }
  816. }
  817. static termline *decompressline_no_free(compressed_scrollback_line *line)
  818. {
  819. int ncols, byte, shift;
  820. BinarySource bs[1];
  821. termline *ldata;
  822. BinarySource_BARE_INIT(bs, line+1, line->len);
  823. /*
  824. * First read in the column count.
  825. */
  826. ncols = shift = 0;
  827. do {
  828. byte = get_byte(bs);
  829. ncols |= (byte & 0x7F) << shift;
  830. shift += 7;
  831. } while (byte & 0x80);
  832. /*
  833. * Now create the output termline.
  834. */
  835. ldata = snew(termline);
  836. ldata->chars = snewn(ncols, termchar);
  837. ldata->cols = ldata->size = ncols;
  838. ldata->temporary = true;
  839. ldata->cc_free = 0;
  840. /*
  841. * We must set all the cc pointers in ldata->chars to 0 right
  842. * now, so that cc diagnostics that verify the integrity of the
  843. * whole line will make sense while we're in the middle of
  844. * building it up.
  845. */
  846. {
  847. int i;
  848. for (i = 0; i < ldata->cols; i++)
  849. ldata->chars[i].cc_next = 0;
  850. }
  851. /*
  852. * Now read in the lattr.
  853. */
  854. int lattr = shift = 0;
  855. do {
  856. byte = get_byte(bs);
  857. lattr |= (byte & 0x7F) << shift;
  858. shift += 7;
  859. } while (byte & 0x80);
  860. ldata->lattr = lattr & 0xFFFF;
  861. ldata->trusted = (lattr & 0x10000) != 0;
  862. /*
  863. * Now we read in each of the RLE streams in turn.
  864. */
  865. readrle(bs, ldata, readliteral_chr);
  866. readrle(bs, ldata, readliteral_attr);
  867. readrle(bs, ldata, readliteral_truecolour);
  868. readrle(bs, ldata, readliteral_cc);
  869. /* And we always expect that we ended up exactly at the end of the
  870. * compressed data. */
  871. assert(!get_err(bs));
  872. assert(get_avail(bs) == 0);
  873. return ldata;
  874. }
  875. static inline void free_compressed_line(compressed_scrollback_line *cline)
  876. {
  877. sfree(cline);
  878. }
  879. static termline *decompressline_and_free(compressed_scrollback_line *cline)
  880. {
  881. termline *ldata = decompressline_no_free(cline);
  882. free_compressed_line(cline);
  883. return ldata;
  884. }
  885. #else /* NO_SCROLLBACK_COMPRESSION */
  886. static termline *duptermline(termline *oldline)
  887. {
  888. termline *newline = snew(termline);
  889. *newline = *oldline; /* copy the POD structure fields */
  890. newline->chars = snewn(newline->size, termchar);
  891. for (int j = 0; j < newline->size; j++)
  892. newline->chars[j] = oldline->chars[j];
  893. return newline;
  894. }
  895. typedef termline compressed_scrollback_line;
  896. static inline compressed_scrollback_line *compressline_and_free(
  897. termline *ldata)
  898. {
  899. return ldata;
  900. }
  901. static inline compressed_scrollback_line *compressline_no_free(termline *ldata)
  902. {
  903. return duptermline(ldata);
  904. }
  905. static inline termline *decompressline_no_free(
  906. compressed_scrollback_line *line)
  907. {
  908. /* This will return a line without the 'temporary' flag, which
  909. * means that unlineptr() is already set up to avoid freeing it */
  910. return line;
  911. }
  912. static inline termline *decompressline_and_free(
  913. compressed_scrollback_line *line)
  914. {
  915. /* Same as decompressline_no_free, because the caller will free
  916. * our returned termline, and that does all the freeing necessary */
  917. return line;
  918. }
  919. static inline void free_compressed_line(compressed_scrollback_line *line)
  920. {
  921. freetermline(line);
  922. }
  923. #endif /* NO_SCROLLBACK_COMPRESSION */
  924. /*
  925. * Resize a line to make it `cols' columns wide.
  926. */
  927. static void resizeline(Terminal *term, termline *line, int cols)
  928. {
  929. int i, oldcols;
  930. if (line->cols != cols) {
  931. oldcols = line->cols;
  932. /*
  933. * This line is the wrong length, which probably means it
  934. * hasn't been accessed since a resize. Resize it now.
  935. *
  936. * First, go through all the characters that will be thrown
  937. * out in the resize (if we're shrinking the line) and
  938. * return their cc lists to the cc free list.
  939. */
  940. for (i = cols; i < oldcols; i++)
  941. clear_cc(line, i);
  942. /*
  943. * If we're shrinking the line, we now bodily move the
  944. * entire cc section from where it started to where it now
  945. * needs to be. (We have to do this before the resize, so
  946. * that the data we're copying is still there. However, if
  947. * we're expanding, we have to wait until _after_ the
  948. * resize so that the space we're copying into is there.)
  949. */
  950. if (cols < oldcols)
  951. memmove(line->chars + cols, line->chars + oldcols,
  952. (line->size - line->cols) * TSIZE);
  953. /*
  954. * Now do the actual resize, leaving the _same_ amount of
  955. * cc space as there was to begin with.
  956. */
  957. line->size += cols - oldcols;
  958. line->chars = sresize(line->chars, line->size, TTYPE);
  959. line->cols = cols;
  960. /*
  961. * If we're expanding the line, _now_ we move the cc
  962. * section.
  963. */
  964. if (cols > oldcols)
  965. memmove(line->chars + cols, line->chars + oldcols,
  966. (line->size - line->cols) * TSIZE);
  967. /*
  968. * Go through what's left of the original line, and adjust
  969. * the first cc_next pointer in each list. (All the
  970. * subsequent ones are still valid because they are
  971. * relative offsets within the cc block.) Also do the same
  972. * to the head of the cc_free list.
  973. */
  974. for (i = 0; i < oldcols && i < cols; i++)
  975. if (line->chars[i].cc_next)
  976. line->chars[i].cc_next += cols - oldcols;
  977. if (line->cc_free)
  978. line->cc_free += cols - oldcols;
  979. /*
  980. * And finally fill in the new space with erase chars. (We
  981. * don't have to worry about cc lists here, because we
  982. * _know_ the erase char doesn't have one.)
  983. */
  984. for (i = oldcols; i < cols; i++)
  985. line->chars[i] = term->basic_erase_char;
  986. #ifdef TERM_CC_DIAGS
  987. cc_check(line);
  988. #endif
  989. }
  990. }
  991. /*
  992. * Get the number of lines in the scrollback.
  993. */
  994. static int sblines(Terminal *term)
  995. {
  996. int sblines = count234(term->scrollback);
  997. if (term->erase_to_scrollback &&
  998. term->alt_which && term->alt_screen) {
  999. sblines += term->alt_sblines;
  1000. }
  1001. return sblines;
  1002. }
  1003. static void null_line_error(Terminal *term, int y, int lineno,
  1004. tree234 *whichtree, int treeindex,
  1005. const char *varname)
  1006. {
  1007. modalfatalbox("%s==NULL in terminal.c\n"
  1008. "lineno=%d y=%d w=%d h=%d\n"
  1009. "count(scrollback=%p)=%d\n"
  1010. "count(screen=%p)=%d\n"
  1011. "count(alt=%p)=%d alt_sblines=%d\n"
  1012. "whichtree=%p treeindex=%d\n"
  1013. "commitid=%s\n\n"
  1014. "Please contact <putty@projects.tartarus.org> "
  1015. "and pass on the above information.",
  1016. varname, lineno, y, term->cols, term->rows,
  1017. term->scrollback, count234(term->scrollback),
  1018. term->screen, count234(term->screen),
  1019. term->alt_screen, count234(term->alt_screen),
  1020. term->alt_sblines, whichtree, treeindex, commitid);
  1021. }
  1022. static inline int checkscr(int y, int lineno)
  1023. {
  1024. if (y < 0)
  1025. modalfatalbox("screen line %d < 0 in terminal.c:%d", y, lineno);
  1026. return y;
  1027. }
  1028. /*
  1029. * Retrieve a line of the screen or of the scrollback, according to
  1030. * whether the y coordinate is non-negative or negative
  1031. * (respectively).
  1032. */
  1033. static termline *lineptr(Terminal *term, int y, int lineno)
  1034. {
  1035. termline *line;
  1036. tree234 *whichtree;
  1037. int treeindex;
  1038. if (y >= 0) {
  1039. whichtree = term->screen;
  1040. treeindex = y;
  1041. } else {
  1042. int altlines = 0;
  1043. if (term->erase_to_scrollback &&
  1044. term->alt_which && term->alt_screen) {
  1045. altlines = term->alt_sblines;
  1046. }
  1047. if (y < -altlines) {
  1048. whichtree = term->scrollback;
  1049. treeindex = y + altlines + count234(term->scrollback);
  1050. } else {
  1051. whichtree = term->alt_screen;
  1052. treeindex = y + term->alt_sblines;
  1053. /* treeindex = y + count234(term->alt_screen); */
  1054. }
  1055. }
  1056. if (whichtree == term->scrollback) {
  1057. compressed_scrollback_line *cline = index234(whichtree, treeindex);
  1058. if (!cline)
  1059. null_line_error(term, y, lineno, whichtree, treeindex, "cline");
  1060. line = decompressline_no_free(cline);
  1061. } else {
  1062. line = index234(whichtree, treeindex);
  1063. }
  1064. /* We assume that we don't screw up and retrieve something out of range. */
  1065. if (line == NULL)
  1066. null_line_error(term, y, lineno, whichtree, treeindex, "line");
  1067. assert(line != NULL);
  1068. /*
  1069. * Here we resize lines to _at least_ the right length, but we
  1070. * don't truncate them. Truncation is done as a side effect of
  1071. * modifying the line.
  1072. *
  1073. * The point of this policy is to try to arrange that resizing the
  1074. * terminal window repeatedly - e.g. successive steps in an X11
  1075. * opaque window-resize drag, or resizing as a side effect of
  1076. * retiling by tiling WMs such as xmonad - does not throw away
  1077. * data gratuitously. Specifically, we want a sequence of resize
  1078. * operations with no terminal output between them to have the
  1079. * same effect as a single resize to the ultimate terminal size,
  1080. * and also (for the case in which xmonad narrows a window that's
  1081. * scrolling things) we want scrolling up new text at the bottom
  1082. * of a narrowed window to avoid truncating lines further up when
  1083. * the window is re-widened.
  1084. */
  1085. if (term->cols > line->cols)
  1086. resizeline(term, line, term->cols);
  1087. return line;
  1088. }
  1089. /*
  1090. * Macro wrappers for lineptr. The distinction between lineptr and
  1091. * scrlineptr is that lineptr can retrieve any line, from the screen
  1092. * _or_ from scrollback, and in return, you have to call unlineptr
  1093. * when you're done with it, in case it was a dynamically allocated
  1094. * line decompressed from scrollback that needs freeing. But
  1095. * scrlineptr will only retrieve lines from the active screen (and
  1096. * enforces this by an assertion), which means it's always just
  1097. * returning a pointer to an existing unpacked termline, and you don't
  1098. * have to call unlineptr afterwards. So drawing code (which might
  1099. * need the scrollback) will have to call lineptr/unlineptr, but
  1100. * update code during term_out can call scrlineptr.
  1101. *
  1102. * The 'assertion' in scrlineptr is done using a helper function that
  1103. * returns the input column number, which allows this macro to avoid
  1104. * double-evaluating its argument.
  1105. */
  1106. #define lineptr(x) (lineptr)(term,x,__LINE__)
  1107. #define scrlineptr(x) (lineptr)(term,checkscr(x,__LINE__),__LINE__)
  1108. #define unlineptr(line) term_release_line(line)
  1109. /* Wrapper for external use (e.g. tests), without the __LINE__ parameter */
  1110. termline *term_get_line(Terminal *term, int y) { return lineptr(y); }
  1111. /*
  1112. * Coerce a termline to the terminal's current width. Unlike the
  1113. * optional resize in lineptr() above, this is potentially destructive
  1114. * of text, since it can shrink as well as grow the line.
  1115. *
  1116. * We call this whenever a termline is actually going to be modified.
  1117. * Helpfully, putting a single call to this function in check_boundary
  1118. * deals with _nearly_ all such cases, leaving only a few things like
  1119. * bulk erase and ESC#8 to handle separately.
  1120. */
  1121. static void check_line_size(Terminal *term, termline *line)
  1122. {
  1123. if (term->cols != line->cols) /* trivial optimisation */
  1124. resizeline(term, line, term->cols);
  1125. }
  1126. static void term_schedule_tblink(Terminal *term);
  1127. static void term_schedule_cblink(Terminal *term);
  1128. static void term_update_callback(void *ctx);
  1129. static void term_timer(void *ctx, unsigned long now)
  1130. {
  1131. Terminal *term = (Terminal *)ctx;
  1132. if (term->tblink_pending && now == term->next_tblink) {
  1133. term->tblinker = !term->tblinker;
  1134. term->tblink_pending = false;
  1135. term_schedule_tblink(term);
  1136. term->window_update_pending = true;
  1137. }
  1138. if (term->cblink_pending && now == term->next_cblink) {
  1139. term->cblinker = !term->cblinker;
  1140. term->cblink_pending = false;
  1141. term_schedule_cblink(term);
  1142. term->window_update_pending = true;
  1143. }
  1144. if (term->in_vbell && now == term->vbell_end) {
  1145. term->in_vbell = false;
  1146. term->window_update_pending = true;
  1147. }
  1148. if (term->window_update_cooldown &&
  1149. now == term->window_update_cooldown_end) {
  1150. term->window_update_cooldown = false;
  1151. }
  1152. if (term->window_update_pending)
  1153. term_update_callback(term);
  1154. }
  1155. static void term_update_callback(void *ctx)
  1156. {
  1157. Terminal *term = (Terminal *)ctx;
  1158. if (!term->window_update_pending)
  1159. return;
  1160. if (!term->window_update_cooldown) {
  1161. term_update(term);
  1162. term->window_update_cooldown = true;
  1163. term->window_update_cooldown_end = schedule_timer(
  1164. UPDATE_DELAY, term_timer, term);
  1165. }
  1166. }
  1167. static void term_schedule_update(Terminal *term)
  1168. {
  1169. if (!term->window_update_pending) {
  1170. term->window_update_pending = true;
  1171. queue_toplevel_callback(term_update_callback, term);
  1172. }
  1173. }
  1174. /*
  1175. * Call this whenever the terminal window state changes, to queue an
  1176. * update. This also resets the phase of cursor blinking, so that the
  1177. * cursor remains visible as it moves with the output, and sets a flag
  1178. * to indicate that if we have the 'reset scrollback on display
  1179. * activity' setting enabled, then we should activate it.
  1180. */
  1181. static void seen_disp_event(Terminal *term)
  1182. {
  1183. if (term->scroll_on_disp) {
  1184. term->disptop = 0;
  1185. term->win_scrollbar_update_pending = true;
  1186. }
  1187. term->cblinker = true;
  1188. term->cblink_pending = false;
  1189. term_schedule_cblink(term);
  1190. term_schedule_update(term);
  1191. }
  1192. /*
  1193. * Call when the terminal's blinking-text settings change, or when
  1194. * a text blink has just occurred.
  1195. */
  1196. static void term_schedule_tblink(Terminal *term)
  1197. {
  1198. if (term->blink_is_real) {
  1199. if (!term->tblink_pending)
  1200. term->next_tblink = schedule_timer(TBLINK_DELAY, term_timer, term);
  1201. term->tblink_pending = true;
  1202. } else {
  1203. term->tblinker = true; /* reset when not in use */
  1204. term->tblink_pending = false;
  1205. }
  1206. }
  1207. /*
  1208. * Likewise with cursor blinks.
  1209. */
  1210. static void term_schedule_cblink(Terminal *term)
  1211. {
  1212. if (term->blink_cur && term->has_focus) {
  1213. if (!term->cblink_pending)
  1214. term->next_cblink = schedule_timer(CBLINK_DELAY, term_timer, term);
  1215. term->cblink_pending = true;
  1216. } else {
  1217. term->cblinker = true; /* reset when not in use */
  1218. term->cblink_pending = false;
  1219. }
  1220. }
  1221. /*
  1222. * Call to begin a visual bell.
  1223. */
  1224. static void term_schedule_vbell(Terminal *term, bool already_started,
  1225. long startpoint)
  1226. {
  1227. long ticks_already_gone;
  1228. if (already_started)
  1229. ticks_already_gone = GETTICKCOUNT() - startpoint;
  1230. else
  1231. ticks_already_gone = 0;
  1232. if (ticks_already_gone < VBELL_DELAY) {
  1233. term->in_vbell = true;
  1234. term->vbell_end = schedule_timer(VBELL_DELAY - ticks_already_gone,
  1235. term_timer, term);
  1236. } else {
  1237. term->in_vbell = false;
  1238. }
  1239. }
  1240. /*
  1241. * Set up power-on settings for the terminal.
  1242. * If 'clear' is false, don't actually clear the primary screen, and
  1243. * position the cursor below the last non-blank line (scrolling if
  1244. * necessary).
  1245. */
  1246. static void power_on(Terminal *term, bool clear)
  1247. {
  1248. term->alt_x = term->alt_y = 0;
  1249. term->savecurs.x = term->savecurs.y = 0;
  1250. term->alt_savecurs.x = term->alt_savecurs.y = 0;
  1251. term->alt_t = term->marg_t = 0;
  1252. if (term->rows != -1)
  1253. term->alt_b = term->marg_b = term->rows - 1;
  1254. else
  1255. term->alt_b = term->marg_b = 0;
  1256. if (term->cols != -1) {
  1257. int i;
  1258. for (i = 0; i < term->cols; i++)
  1259. term->tabs[i] = (i % 8 == 0 ? true : false);
  1260. }
  1261. term->alt_om = term->dec_om = conf_get_bool(term->conf, CONF_dec_om);
  1262. term->alt_ins = false;
  1263. term->insert = false;
  1264. term->alt_wnext = false;
  1265. term->wrapnext = false;
  1266. term->save_wnext = false;
  1267. term->alt_save_wnext = false;
  1268. term->alt_wrap = term->wrap = conf_get_bool(term->conf, CONF_wrap_mode);
  1269. term->alt_cset = term->cset = term->save_cset = term->alt_save_cset = 0;
  1270. term->alt_utf = false;
  1271. term->utf = false;
  1272. term->save_utf = false;
  1273. term->alt_save_utf = false;
  1274. term->utf8.state = 0;
  1275. term->alt_sco_acs = term->sco_acs =
  1276. term->save_sco_acs = term->alt_save_sco_acs = 0;
  1277. term->cset_attr[0] = term->cset_attr[1] =
  1278. term->save_csattr = term->alt_save_csattr = CSET_ASCII;
  1279. term->rvideo = false;
  1280. term->in_vbell = false;
  1281. term->cursor_on = true;
  1282. term->big_cursor = false;
  1283. term->default_attr = term->save_attr =
  1284. term->alt_save_attr = term->curr_attr = ATTR_DEFAULT;
  1285. term->curr_truecolour.fg = term->curr_truecolour.bg = optionalrgb_none;
  1286. term->save_truecolour = term->alt_save_truecolour = term->curr_truecolour;
  1287. term->app_cursor_keys = conf_get_bool(term->conf, CONF_app_cursor);
  1288. term->app_keypad_keys = conf_get_bool(term->conf, CONF_app_keypad);
  1289. term->use_bce = conf_get_bool(term->conf, CONF_bce);
  1290. term->blink_is_real = conf_get_bool(term->conf, CONF_blinktext);
  1291. term->erase_char = term->basic_erase_char;
  1292. term->alt_which = 0;
  1293. term_print_finish(term);
  1294. term->xterm_mouse = 0;
  1295. term->xterm_extended_mouse = false;
  1296. term->urxvt_extended_mouse = false;
  1297. term->raw_mouse_reported_x = 0;
  1298. term->raw_mouse_reported_y = 0;
  1299. win_set_raw_mouse_mode(term->win, false);
  1300. term->win_pointer_shape_pending = true;
  1301. term->win_pointer_shape_raw = false;
  1302. term->bracketed_paste = false;
  1303. term->srm_echo = false;
  1304. {
  1305. int i;
  1306. for (i = 0; i < 256; i++)
  1307. term->wordness[i] = conf_get_int_int(term->conf, CONF_wordness, i);
  1308. }
  1309. if (term->screen) {
  1310. swap_screen(term, 1, false, false);
  1311. erase_lots(term, false, true, true);
  1312. swap_screen(term, 0, false, false);
  1313. if (clear)
  1314. erase_lots(term, false, true, true);
  1315. term->curs.y = find_last_nonempty_line(term, term->screen) + 1;
  1316. if (term->curs.y == term->rows) {
  1317. term->curs.y--;
  1318. scroll(term, 0, term->rows - 1, 1, true);
  1319. }
  1320. } else {
  1321. term->curs.y = 0;
  1322. }
  1323. term->curs.x = 0;
  1324. term_schedule_tblink(term);
  1325. term_schedule_cblink(term);
  1326. term_schedule_update(term);
  1327. }
  1328. /*
  1329. * Force a screen update.
  1330. */
  1331. void term_update(Terminal *term)
  1332. {
  1333. term->window_update_pending = false;
  1334. if (term->win_move_pending) {
  1335. win_move(term->win, term->win_move_pending_x,
  1336. term->win_move_pending_y);
  1337. term->win_move_pending = false;
  1338. }
  1339. if (term->win_resize_pending == WIN_RESIZE_NEED_SEND) {
  1340. term->win_resize_pending = WIN_RESIZE_AWAIT_REPLY;
  1341. win_request_resize(term->win, term->win_resize_pending_w,
  1342. term->win_resize_pending_h);
  1343. }
  1344. if (term->win_zorder_pending) {
  1345. win_set_zorder(term->win, term->win_zorder_top);
  1346. term->win_zorder_pending = false;
  1347. }
  1348. if (term->win_minimise_pending) {
  1349. win_set_minimised(term->win, term->win_minimise_enable);
  1350. term->win_minimise_pending = false;
  1351. }
  1352. if (term->win_maximise_pending) {
  1353. win_set_maximised(term->win, term->win_maximise_enable);
  1354. term->win_maximise_pending = false;
  1355. }
  1356. if (term->win_title_pending) {
  1357. win_set_title(term->win, term->window_title,
  1358. term->wintitle_codepage);
  1359. term->win_title_pending = false;
  1360. }
  1361. if (term->win_icon_title_pending) {
  1362. win_set_icon_title(term->win, term->icon_title,
  1363. term->icontitle_codepage);
  1364. term->win_icon_title_pending = false;
  1365. }
  1366. if (term->win_pointer_shape_pending) {
  1367. win_set_raw_mouse_mode_pointer(term->win, term->win_pointer_shape_raw);
  1368. term->win_pointer_shape_pending = false;
  1369. }
  1370. if (term->win_refresh_pending) {
  1371. win_refresh(term->win);
  1372. term->win_refresh_pending = false;
  1373. }
  1374. if (term->win_palette_pending) {
  1375. unsigned start = term->win_palette_pending_min;
  1376. unsigned ncolours = term->win_palette_pending_limit - start;
  1377. win_palette_set(term->win, start, ncolours, term->palette + start);
  1378. term->win_palette_pending = false;
  1379. }
  1380. if (win_setup_draw_ctx(term->win)) {
  1381. if (term->win_scrollbar_update_pending) {
  1382. term->win_scrollbar_update_pending = false;
  1383. update_sbar(term);
  1384. }
  1385. do_paint(term);
  1386. win_set_cursor_pos(
  1387. term->win, term->curs.x, term->curs.y - term->disptop);
  1388. win_free_draw_ctx(term->win);
  1389. }
  1390. }
  1391. /*
  1392. * Called from front end when a keypress occurs, to trigger
  1393. * anything magical that needs to happen in that situation.
  1394. */
  1395. void term_seen_key_event(Terminal *term)
  1396. {
  1397. /*
  1398. * On any keypress, clear the bell overload mechanism
  1399. * completely, on the grounds that large numbers of
  1400. * beeps coming from deliberate key action are likely
  1401. * to be intended (e.g. beeps from filename completion
  1402. * blocking repeatedly).
  1403. */
  1404. term->beep_overloaded = false;
  1405. while (term->beephead) {
  1406. struct beeptime *tmp = term->beephead;
  1407. term->beephead = tmp->next;
  1408. sfree(tmp);
  1409. }
  1410. term->beeptail = NULL;
  1411. term->nbeeps = 0;
  1412. /*
  1413. * Reset the scrollback on keypress, if we're doing that.
  1414. */
  1415. if (term->scroll_on_key && term->disptop != 0) {
  1416. term->disptop = 0;
  1417. term->win_scrollbar_update_pending = true;
  1418. term_schedule_update(term);
  1419. }
  1420. }
  1421. /*
  1422. * Same as power_on(), but an external function.
  1423. */
  1424. void term_pwron(Terminal *term, bool clear)
  1425. {
  1426. power_on(term, clear);
  1427. if (term->ldisc) /* cause ldisc to notice changes */
  1428. ldisc_echoedit_update(term->ldisc);
  1429. term->disptop = 0;
  1430. deselect(term);
  1431. term_update(term);
  1432. }
  1433. static void set_erase_char(Terminal *term)
  1434. {
  1435. term->erase_char = term->basic_erase_char;
  1436. if (term->use_bce) {
  1437. term->erase_char.attr = (term->curr_attr &
  1438. (ATTR_FGMASK | ATTR_BGMASK));
  1439. term->erase_char.truecolour.bg = term->curr_truecolour.bg;
  1440. }
  1441. }
  1442. /*
  1443. * We copy a bunch of stuff out of the Conf structure into local
  1444. * fields in the Terminal structure, to avoid the repeated tree234
  1445. * lookups which would be involved in fetching them from the former
  1446. * every time.
  1447. */
  1448. static void term_copy_stuff_from_conf(Terminal *term)
  1449. {
  1450. term->ansi_colour = conf_get_bool(term->conf, CONF_ansi_colour);
  1451. term->no_arabicshaping = conf_get_bool(term->conf, CONF_no_arabicshaping);
  1452. term->beep = conf_get_int(term->conf, CONF_beep);
  1453. term->bellovl = conf_get_bool(term->conf, CONF_bellovl);
  1454. term->bellovl_n = conf_get_int(term->conf, CONF_bellovl_n);
  1455. term->bellovl_s = conf_get_int(term->conf, CONF_bellovl_s);
  1456. term->bellovl_t = conf_get_int(term->conf, CONF_bellovl_t);
  1457. term->no_bidi = conf_get_bool(term->conf, CONF_no_bidi);
  1458. term->no_bracketed_paste = conf_get_bool(term->conf, CONF_no_bracketed_paste);
  1459. term->bksp_is_delete = conf_get_bool(term->conf, CONF_bksp_is_delete);
  1460. term->blink_cur = conf_get_bool(term->conf, CONF_blink_cur);
  1461. term->blinktext = conf_get_bool(term->conf, CONF_blinktext);
  1462. term->cjk_ambig_wide = conf_get_bool(term->conf, CONF_cjk_ambig_wide);
  1463. term->conf_height = conf_get_int(term->conf, CONF_height);
  1464. term->conf_width = conf_get_int(term->conf, CONF_width);
  1465. term->crhaslf = conf_get_bool(term->conf, CONF_crhaslf);
  1466. term->erase_to_scrollback = conf_get_bool(term->conf, CONF_erase_to_scrollback);
  1467. term->funky_type = conf_get_int(term->conf, CONF_funky_type);
  1468. term->sharrow_type = conf_get_int(term->conf, CONF_sharrow_type);
  1469. term->lfhascr = conf_get_bool(term->conf, CONF_lfhascr);
  1470. term->logflush = conf_get_bool(term->conf, CONF_logflush);
  1471. term->logtype = conf_get_int(term->conf, CONF_logtype);
  1472. term->mouse_override = conf_get_bool(term->conf, CONF_mouse_override);
  1473. term->nethack_keypad = conf_get_bool(term->conf, CONF_nethack_keypad);
  1474. term->no_alt_screen = conf_get_bool(term->conf, CONF_no_alt_screen);
  1475. term->no_applic_c = conf_get_bool(term->conf, CONF_no_applic_c);
  1476. term->no_applic_k = conf_get_bool(term->conf, CONF_no_applic_k);
  1477. term->no_dbackspace = conf_get_bool(term->conf, CONF_no_dbackspace);
  1478. term->no_mouse_rep = conf_get_bool(term->conf, CONF_no_mouse_rep);
  1479. term->no_remote_charset = conf_get_bool(term->conf, CONF_no_remote_charset);
  1480. term->no_remote_resize = conf_get_bool(term->conf, CONF_no_remote_resize);
  1481. term->no_remote_wintitle = conf_get_bool(term->conf, CONF_no_remote_wintitle);
  1482. term->no_remote_clearscroll = conf_get_bool(term->conf, CONF_no_remote_clearscroll);
  1483. term->rawcnp = conf_get_bool(term->conf, CONF_rawcnp);
  1484. term->utf8linedraw = conf_get_bool(term->conf, CONF_utf8linedraw);
  1485. term->rect_select = conf_get_bool(term->conf, CONF_rect_select);
  1486. term->remote_qtitle_action = conf_get_int(term->conf, CONF_remote_qtitle_action);
  1487. term->rxvt_homeend = conf_get_bool(term->conf, CONF_rxvt_homeend);
  1488. term->scroll_on_disp = conf_get_bool(term->conf, CONF_scroll_on_disp);
  1489. term->scroll_on_key = conf_get_bool(term->conf, CONF_scroll_on_key);
  1490. term->xterm_mouse_forbidden = conf_get_bool(term->conf, CONF_no_mouse_rep);
  1491. term->xterm_256_colour = conf_get_bool(term->conf, CONF_xterm_256_colour);
  1492. term->true_colour = conf_get_bool(term->conf, CONF_true_colour);
  1493. /*
  1494. * Parse the control-character escapes in the configured
  1495. * answerback string.
  1496. */
  1497. {
  1498. char *answerback = conf_get_str(term->conf, CONF_answerback);
  1499. strbuf_clear(term->answerback);
  1500. while (*answerback) {
  1501. char *n;
  1502. char c = ctrlparse(answerback, &n);
  1503. if (n) {
  1504. put_byte(term->answerback, c);
  1505. answerback = n;
  1506. } else {
  1507. put_byte(term->answerback, *answerback++);
  1508. }
  1509. }
  1510. }
  1511. }
  1512. void term_pre_reconfig(Terminal *term, Conf *conf)
  1513. {
  1514. /*
  1515. * Copy the current window title into the stored previous
  1516. * configuration, so that doing nothing to the window title field
  1517. * in the config box doesn't reset the title to its startup state.
  1518. */
  1519. conf_set_str(conf, CONF_wintitle, term->window_title);
  1520. }
  1521. /*
  1522. * When the user reconfigures us, we need to check the forbidden-
  1523. * alternate-screen config option, disable raw mouse mode if the
  1524. * user has disabled mouse reporting, and abandon a print job if
  1525. * the user has disabled printing.
  1526. */
  1527. void term_reconfig(Terminal *term, Conf *conf)
  1528. {
  1529. /*
  1530. * Before adopting the new config, check all those terminal
  1531. * settings which control power-on defaults; and if they've
  1532. * changed, we will modify the current state as well as the
  1533. * default one. The full list is: Auto wrap mode, DEC Origin
  1534. * Mode, BCE, blinking text, character classes.
  1535. */
  1536. bool reset_wrap, reset_decom, reset_bce, reset_tblink, reset_charclass;
  1537. bool palette_changed = false;
  1538. int i;
  1539. reset_wrap = (conf_get_bool(term->conf, CONF_wrap_mode) !=
  1540. conf_get_bool(conf, CONF_wrap_mode));
  1541. reset_decom = (conf_get_bool(term->conf, CONF_dec_om) !=
  1542. conf_get_bool(conf, CONF_dec_om));
  1543. reset_bce = (conf_get_bool(term->conf, CONF_bce) !=
  1544. conf_get_bool(conf, CONF_bce));
  1545. reset_tblink = (conf_get_bool(term->conf, CONF_blinktext) !=
  1546. conf_get_bool(conf, CONF_blinktext));
  1547. reset_charclass = false;
  1548. for (i = 0; i < 256; i++)
  1549. if (conf_get_int_int(term->conf, CONF_wordness, i) !=
  1550. conf_get_int_int(conf, CONF_wordness, i))
  1551. reset_charclass = true;
  1552. /*
  1553. * If the bidi or shaping settings have changed, flush the bidi
  1554. * cache completely.
  1555. */
  1556. if (conf_get_bool(term->conf, CONF_no_arabicshaping) !=
  1557. conf_get_bool(conf, CONF_no_arabicshaping) ||
  1558. conf_get_bool(term->conf, CONF_no_bidi) !=
  1559. conf_get_bool(conf, CONF_no_bidi)) {
  1560. for (i = 0; i < term->bidi_cache_size; i++) {
  1561. sfree(term->pre_bidi_cache[i].chars);
  1562. sfree(term->post_bidi_cache[i].chars);
  1563. term->pre_bidi_cache[i].width = -1;
  1564. term->pre_bidi_cache[i].chars = NULL;
  1565. term->post_bidi_cache[i].width = -1;
  1566. term->post_bidi_cache[i].chars = NULL;
  1567. }
  1568. }
  1569. {
  1570. const char *old_title = conf_get_str(term->conf, CONF_wintitle);
  1571. const char *new_title = conf_get_str(conf, CONF_wintitle);
  1572. if (strcmp(old_title, new_title)) {
  1573. sfree(term->window_title);
  1574. term->window_title = dupstr(new_title);
  1575. term->wintitle_codepage = DEFAULT_CODEPAGE;
  1576. term->win_title_pending = true;
  1577. term_schedule_update(term);
  1578. }
  1579. }
  1580. /*
  1581. * Just setting conf is sufficient to cause colour setting changes
  1582. * to appear on the next ESC]R palette reset. But we should also
  1583. * check whether any colour settings have been changed, so that
  1584. * they can be updated immediately if they haven't been overridden
  1585. * by some escape sequence.
  1586. */
  1587. {
  1588. int i, j;
  1589. for (i = 0; i < CONF_NCOLOURS; i++) {
  1590. for (j = 0; j < 3; j++)
  1591. if (conf_get_int_int(term->conf, CONF_colours, i*3+j) !=
  1592. conf_get_int_int(conf, CONF_colours, i*3+j))
  1593. break;
  1594. if (j < 3) {
  1595. /* Actually enacting the change has to be deferred
  1596. * until the new conf is installed. */
  1597. palette_changed = true;
  1598. break;
  1599. }
  1600. }
  1601. }
  1602. conf_free(term->conf);
  1603. term->conf = conf_copy(conf);
  1604. if (reset_wrap) {
  1605. term->alt_wrap = term->wrap = conf_get_bool(term->conf, CONF_wrap_mode);
  1606. if (!term->wrap)
  1607. term->wrapnext = false;
  1608. if (!term->alt_wrap)
  1609. term->alt_wnext = false;
  1610. }
  1611. if (reset_decom)
  1612. term->alt_om = term->dec_om = conf_get_bool(term->conf, CONF_dec_om);
  1613. if (reset_bce) {
  1614. term->use_bce = conf_get_bool(term->conf, CONF_bce);
  1615. set_erase_char(term);
  1616. }
  1617. if (reset_tblink) {
  1618. term->blink_is_real = conf_get_bool(term->conf, CONF_blinktext);
  1619. }
  1620. if (reset_charclass)
  1621. for (i = 0; i < 256; i++)
  1622. term->wordness[i] = conf_get_int_int(term->conf, CONF_wordness, i);
  1623. if (conf_get_bool(term->conf, CONF_no_alt_screen))
  1624. swap_screen(term, 0, false, false);
  1625. if (conf_get_bool(term->conf, CONF_no_remote_charset)) {
  1626. term->cset_attr[0] = term->cset_attr[1] = CSET_ASCII;
  1627. term->sco_acs = term->alt_sco_acs = 0;
  1628. term->utf = false;
  1629. }
  1630. if (!conf_get_str(term->conf, CONF_printer)) {
  1631. term_print_finish(term);
  1632. }
  1633. if (palette_changed)
  1634. term_notify_palette_changed(term);
  1635. term_schedule_tblink(term);
  1636. term_schedule_cblink(term);
  1637. term_copy_stuff_from_conf(term);
  1638. term_update_raw_mouse_mode(term);
  1639. }
  1640. /*
  1641. * Clear the scrollback.
  1642. */
  1643. void term_clrsb(Terminal *term)
  1644. {
  1645. unsigned char *line;
  1646. int i;
  1647. /*
  1648. * Scroll forward to the current screen, if we were back in the
  1649. * scrollback somewhere until now.
  1650. */
  1651. term->disptop = 0;
  1652. /*
  1653. * Clear the actual scrollback.
  1654. */
  1655. while ((line = delpos234(term->scrollback, 0)) != NULL) {
  1656. sfree(line); /* this is compressed data, not a termline */
  1657. }
  1658. /*
  1659. * When clearing the scrollback, we also truncate any termlines on
  1660. * the current screen which have remembered data from a previous
  1661. * larger window size. Rationale: clearing the scrollback is
  1662. * sometimes done to protect privacy, so the user intention is
  1663. * specifically that we should not retain evidence of what
  1664. * previously happened in the terminal, and that ought to include
  1665. * evidence to the right as well as evidence above.
  1666. */
  1667. for (i = 0; i < term->rows; i++)
  1668. check_line_size(term, scrlineptr(i));
  1669. /*
  1670. * That operation has invalidated the selection, if it overlapped
  1671. * the scrollback at all.
  1672. */
  1673. if (term->selstate != NO_SELECTION && term->selstart.y < 0)
  1674. deselect(term);
  1675. /*
  1676. * There are now no lines of real scrollback which can be pulled
  1677. * back into the screen by a resize, and no lines of the alternate
  1678. * screen which should be displayed as if part of the scrollback.
  1679. */
  1680. term->tempsblines = 0;
  1681. term->alt_sblines = 0;
  1682. /*
  1683. * The scrollbar will need updating to reflect the new state of
  1684. * the world.
  1685. */
  1686. term->win_scrollbar_update_pending = true;
  1687. term_schedule_update(term);
  1688. }
  1689. const optionalrgb optionalrgb_none = {0, 0, 0, 0};
  1690. void term_setup_window_titles(Terminal *term, const char *title_hostname)
  1691. {
  1692. const char *conf_title = conf_get_str(term->conf, CONF_wintitle);
  1693. sfree(term->window_title);
  1694. sfree(term->icon_title);
  1695. if (*conf_title) {
  1696. term->window_title = dupstr(conf_title);
  1697. term->icon_title = dupstr(conf_title);
  1698. } else {
  1699. if (title_hostname && *title_hostname)
  1700. term->window_title = dupcat(title_hostname, " - ", appname);
  1701. else
  1702. term->window_title = dupstr(appname);
  1703. term->icon_title = dupstr(term->window_title);
  1704. }
  1705. term->wintitle_codepage = term->icontitle_codepage = DEFAULT_CODEPAGE;
  1706. term->win_title_pending = true;
  1707. term->win_icon_title_pending = true;
  1708. }
  1709. static void palette_rebuild(Terminal *term)
  1710. {
  1711. unsigned min_changed = OSC4_NCOLOURS, max_changed = 0;
  1712. if (term->win_palette_pending) {
  1713. /* Possibly extend existing range. */
  1714. min_changed = term->win_palette_pending_min;
  1715. max_changed = term->win_palette_pending_limit - 1;
  1716. } else {
  1717. /* Start with empty range. */
  1718. min_changed = OSC4_NCOLOURS;
  1719. max_changed = 0;
  1720. }
  1721. for (unsigned i = 0; i < OSC4_NCOLOURS; i++) {
  1722. rgb new_value;
  1723. bool found = false;
  1724. for (unsigned j = lenof(term->subpalettes); j-- > 0 ;) {
  1725. if (term->subpalettes[j].present[i]) {
  1726. new_value = term->subpalettes[j].values[i];
  1727. found = true;
  1728. break;
  1729. }
  1730. }
  1731. assert(found); /* we expect SUBPAL_CONF to always be set */
  1732. if (new_value.r != term->palette[i].r ||
  1733. new_value.g != term->palette[i].g ||
  1734. new_value.b != term->palette[i].b) {
  1735. term->palette[i] = new_value;
  1736. if (min_changed > i)
  1737. min_changed = i;
  1738. if (max_changed < i)
  1739. max_changed = i;
  1740. }
  1741. }
  1742. if (min_changed <= max_changed) {
  1743. /*
  1744. * At least one colour changed (or we had an update scheduled
  1745. * already). Schedule a redraw event to pass the result back
  1746. * to the TermWin. This also requires invalidating the rest
  1747. * of the window, because usually all the text will need
  1748. * redrawing in the new colours.
  1749. * (If there was an update pending and this palette rebuild
  1750. * didn't actually change anything, we'll harmlessly reinforce
  1751. * the existing update request.)
  1752. */
  1753. term->win_palette_pending = true;
  1754. term->win_palette_pending_min = min_changed;
  1755. term->win_palette_pending_limit = max_changed + 1;
  1756. term_invalidate(term);
  1757. }
  1758. }
  1759. /*
  1760. * Rebuild the palette from configuration and platform colours.
  1761. * If 'keep_overrides' set, any escape-sequence-specified overrides will
  1762. * remain in place.
  1763. */
  1764. static void palette_reset(Terminal *term, bool keep_overrides)
  1765. {
  1766. for (unsigned i = 0; i < OSC4_NCOLOURS; i++)
  1767. term->subpalettes[SUBPAL_CONF].present[i] = true;
  1768. /*
  1769. * Copy all the palette information out of the Conf.
  1770. */
  1771. for (unsigned i = 0; i < CONF_NCOLOURS; i++) {
  1772. rgb *col = &term->subpalettes[SUBPAL_CONF].values[
  1773. colour_indices_conf_to_osc4[i]];
  1774. col->r = conf_get_int_int(term->conf, CONF_colours, i*3+0);
  1775. col->g = conf_get_int_int(term->conf, CONF_colours, i*3+1);
  1776. col->b = conf_get_int_int(term->conf, CONF_colours, i*3+2);
  1777. }
  1778. /*
  1779. * Directly invent the rest of the xterm-256 colours.
  1780. */
  1781. for (unsigned i = 0; i < 216; i++) {
  1782. rgb *col = &term->subpalettes[SUBPAL_CONF].values[i + 16];
  1783. int r = i / 36, g = (i / 6) % 6, b = i % 6;
  1784. col->r = r ? r * 40 + 55 : 0;
  1785. col->g = g ? g * 40 + 55 : 0;
  1786. col->b = b ? b * 40 + 55 : 0;
  1787. }
  1788. for (unsigned i = 0; i < 24; i++) {
  1789. rgb *col = &term->subpalettes[SUBPAL_CONF].values[i + 232];
  1790. int shade = i * 10 + 8;
  1791. col->r = col->g = col->b = shade;
  1792. }
  1793. /*
  1794. * Re-fetch any OS-local overrides.
  1795. */
  1796. for (unsigned i = 0; i < OSC4_NCOLOURS; i++)
  1797. term->subpalettes[SUBPAL_PLATFORM].present[i] = false;
  1798. win_palette_get_overrides(term->win, term);
  1799. if (!keep_overrides) {
  1800. /*
  1801. * Get rid of all escape-sequence configuration.
  1802. */
  1803. for (unsigned i = 0; i < OSC4_NCOLOURS; i++)
  1804. term->subpalettes[SUBPAL_SESSION].present[i] = false;
  1805. }
  1806. /*
  1807. * Rebuild the composite palette.
  1808. */
  1809. palette_rebuild(term);
  1810. }
  1811. void term_palette_override(Terminal *term, unsigned osc4_index, rgb rgb)
  1812. {
  1813. /*
  1814. * We never expect to be called except as re-entry from our own
  1815. * call to win_palette_get_overrides above, so we need not mess
  1816. * about calling palette_rebuild.
  1817. */
  1818. term->subpalettes[SUBPAL_PLATFORM].present[osc4_index] = true;
  1819. term->subpalettes[SUBPAL_PLATFORM].values[osc4_index] = rgb;
  1820. }
  1821. /*
  1822. * Initialise the terminal.
  1823. */
  1824. Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, TermWin *win)
  1825. {
  1826. Terminal *term;
  1827. /*
  1828. * Allocate a new Terminal structure and initialise the fields
  1829. * that need it.
  1830. */
  1831. term = snew(Terminal);
  1832. memset(term, 0, sizeof(Terminal));
  1833. term->win = win;
  1834. term->ucsdata = ucsdata;
  1835. term->conf = conf_copy(myconf);
  1836. term->compatibility_level = TM_PUTTY;
  1837. strcpy(term->id_string, "\033[?6c");
  1838. bufchain_init(&term->inbuf);
  1839. bufchain_init(&term->printer_buf);
  1840. term->has_focus = true;
  1841. term->termstate = TOPLEVEL;
  1842. term->selstate = NO_SELECTION;
  1843. term->answerback = strbuf_new();
  1844. term_copy_stuff_from_conf(term);
  1845. term->dispcursx = term->dispcursy = -1;
  1846. deselect(term);
  1847. term->rows = term->cols = -1;
  1848. power_on(term, true);
  1849. term->attr_mask = 0xffffffff;
  1850. /* FULL-TERMCHAR */
  1851. term->basic_erase_char.chr = CSET_ASCII | ' ';
  1852. term->basic_erase_char.attr = ATTR_DEFAULT;
  1853. term->basic_erase_char.truecolour.fg = optionalrgb_none;
  1854. term->basic_erase_char.truecolour.bg = optionalrgb_none;
  1855. term->erase_char = term->basic_erase_char;
  1856. /* TermWin implementations will typically extend these with
  1857. * clipboard ids they know about */
  1858. term->mouse_select_clipboards[0] = CLIP_LOCAL;
  1859. term->n_mouse_select_clipboards = 1;
  1860. term->mouse_paste_clipboard = CLIP_NULL;
  1861. term->trusted = true;
  1862. term->window_title = dupstr("");
  1863. term->icon_title = dupstr("");
  1864. term->wintitle_codepage = term->icontitle_codepage = DEFAULT_CODEPAGE;
  1865. term->win_resize_pending = WIN_RESIZE_NO;
  1866. term->bidi_ctx = bidi_new_context();
  1867. palette_reset(term, false);
  1868. return term;
  1869. }
  1870. void term_free(Terminal *term)
  1871. {
  1872. compressed_scrollback_line *cline;
  1873. termline *line;
  1874. struct beeptime *beep;
  1875. int i;
  1876. while ((cline = delpos234(term->scrollback, 0)) != NULL)
  1877. free_compressed_line(cline);
  1878. freetree234(term->scrollback);
  1879. while ((line = delpos234(term->screen, 0)) != NULL)
  1880. freetermline(line);
  1881. freetree234(term->screen);
  1882. while ((line = delpos234(term->alt_screen, 0)) != NULL)
  1883. freetermline(line);
  1884. freetree234(term->alt_screen);
  1885. if (term->disptext) {
  1886. for (i = 0; i < term->rows; i++)
  1887. freetermline(term->disptext[i]);
  1888. }
  1889. sfree(term->disptext);
  1890. while (term->beephead) {
  1891. beep = term->beephead;
  1892. term->beephead = beep->next;
  1893. sfree(beep);
  1894. }
  1895. bufchain_clear(&term->inbuf);
  1896. if (term->print_job)
  1897. printer_finish_job(term->print_job);
  1898. bufchain_clear(&term->printer_buf);
  1899. sfree(term->paste_buffer);
  1900. sfree(term->ltemp);
  1901. sfree(term->wcFrom);
  1902. sfree(term->wcTo);
  1903. strbuf_free(term->answerback);
  1904. for (i = 0; i < term->bidi_cache_size; i++) {
  1905. sfree(term->pre_bidi_cache[i].chars);
  1906. sfree(term->post_bidi_cache[i].chars);
  1907. sfree(term->post_bidi_cache[i].forward);
  1908. sfree(term->post_bidi_cache[i].backward);
  1909. }
  1910. sfree(term->pre_bidi_cache);
  1911. sfree(term->post_bidi_cache);
  1912. sfree(term->tabs);
  1913. expire_timer_context(term);
  1914. delete_callbacks_for_context(term);
  1915. conf_free(term->conf);
  1916. sfree(term->window_title);
  1917. sfree(term->icon_title);
  1918. bidi_free_context(term->bidi_ctx);
  1919. /* In case a term_userpass_state is still around */
  1920. if (term->userpass_state)
  1921. term_userpass_state_free(term->userpass_state);
  1922. sfree(term);
  1923. }
  1924. void term_set_trust_status(Terminal *term, bool trusted)
  1925. {
  1926. term->trusted = trusted;
  1927. }
  1928. void term_get_cursor_position(Terminal *term, int *x, int *y)
  1929. {
  1930. *x = term->curs.x;
  1931. *y = term->curs.y;
  1932. }
  1933. /*
  1934. * Set up the terminal for a given size.
  1935. */
  1936. void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
  1937. {
  1938. tree234 *newalt;
  1939. termline **newdisp, *line;
  1940. int i, j, oldrows = term->rows;
  1941. int sblen;
  1942. int save_alt_which = term->alt_which;
  1943. if (newrows == term->rows && newcols == term->cols &&
  1944. newsavelines == term->savelines)
  1945. return; /* nothing to do */
  1946. /* Behave sensibly if we're given zero (or negative) rows/cols */
  1947. if (newrows < 1) newrows = 1;
  1948. if (newcols < 1) newcols = 1;
  1949. deselect(term);
  1950. swap_screen(term, 0, false, false);
  1951. term->alt_t = term->marg_t = 0;
  1952. term->alt_b = term->marg_b = newrows - 1;
  1953. if (term->rows == -1) {
  1954. term->scrollback = newtree234(NULL);
  1955. term->screen = newtree234(NULL);
  1956. term->tempsblines = 0;
  1957. term->rows = 0;
  1958. }
  1959. /*
  1960. * Resize the screen and scrollback. We only need to shift
  1961. * lines around within our data structures, because lineptr()
  1962. * will take care of resizing each individual line if
  1963. * necessary. So:
  1964. *
  1965. * - If the new screen is longer, we shunt lines in from temporary
  1966. * scrollback if possible, otherwise we add new blank lines at
  1967. * the bottom.
  1968. *
  1969. * - If the new screen is shorter, we remove any blank lines at
  1970. * the bottom if possible, otherwise shunt lines above the cursor
  1971. * to scrollback if possible, otherwise delete lines below the
  1972. * cursor.
  1973. *
  1974. * - Then, if the new scrollback length is less than the
  1975. * amount of scrollback we actually have, we must throw some
  1976. * away.
  1977. */
  1978. sblen = count234(term->scrollback);
  1979. /* Do this loop to expand the screen if newrows > rows */
  1980. assert(term->rows == count234(term->screen));
  1981. while (term->rows < newrows) {
  1982. if (term->tempsblines > 0) {
  1983. compressed_scrollback_line *cline;
  1984. /* Insert a line from the scrollback at the top of the screen. */
  1985. assert(sblen >= term->tempsblines);
  1986. cline = delpos234(term->scrollback, --sblen);
  1987. line = decompressline_and_free(cline);
  1988. line->temporary = false; /* reconstituted line is now real */
  1989. term->tempsblines -= 1;
  1990. addpos234(term->screen, line, 0);
  1991. term->curs.y += 1;
  1992. term->savecurs.y += 1;
  1993. term->alt_y += 1;
  1994. term->alt_savecurs.y += 1;
  1995. } else {
  1996. /* Add a new blank line at the bottom of the screen. */
  1997. line = newtermline(term, newcols, false);
  1998. addpos234(term->screen, line, count234(term->screen));
  1999. }
  2000. term->rows += 1;
  2001. }
  2002. /* Do this loop to shrink the screen if newrows < rows */
  2003. while (term->rows > newrows) {
  2004. if (term->curs.y < term->rows - 1) {
  2005. /* delete bottom row, unless it contains the cursor */
  2006. line = delpos234(term->screen, term->rows - 1);
  2007. freetermline(line);
  2008. } else {
  2009. /* push top row to scrollback */
  2010. line = delpos234(term->screen, 0);
  2011. addpos234(term->scrollback, compressline_and_free(line), sblen++);
  2012. term->tempsblines += 1;
  2013. term->curs.y -= 1;
  2014. term->savecurs.y -= 1;
  2015. term->alt_y -= 1;
  2016. term->alt_savecurs.y -= 1;
  2017. }
  2018. term->rows -= 1;
  2019. }
  2020. assert(term->rows == newrows);
  2021. assert(count234(term->screen) == newrows);
  2022. /* Delete any excess lines from the scrollback. */
  2023. while (sblen > newsavelines) {
  2024. line = delpos234(term->scrollback, 0);
  2025. sfree(line);
  2026. sblen--;
  2027. }
  2028. if (sblen < term->tempsblines)
  2029. term->tempsblines = sblen;
  2030. assert(count234(term->scrollback) <= newsavelines);
  2031. assert(count234(term->scrollback) >= term->tempsblines);
  2032. term->disptop = 0;
  2033. /* Make a new displayed text buffer. */
  2034. newdisp = snewn(newrows, termline *);
  2035. for (i = 0; i < newrows; i++) {
  2036. newdisp[i] = newtermline(term, newcols, false);
  2037. for (j = 0; j < newcols; j++)
  2038. newdisp[i]->chars[j].attr = ATTR_INVALID;
  2039. }
  2040. if (term->disptext) {
  2041. for (i = 0; i < oldrows; i++)
  2042. freetermline(term->disptext[i]);
  2043. }
  2044. sfree(term->disptext);
  2045. term->disptext = newdisp;
  2046. term->dispcursx = term->dispcursy = -1;
  2047. /* Make a new alternate screen. */
  2048. newalt = newtree234(NULL);
  2049. for (i = 0; i < newrows; i++) {
  2050. line = newtermline(term, newcols, true);
  2051. addpos234(newalt, line, i);
  2052. }
  2053. if (term->alt_screen) {
  2054. while (NULL != (line = delpos234(term->alt_screen, 0)))
  2055. freetermline(line);
  2056. freetree234(term->alt_screen);
  2057. }
  2058. term->alt_screen = newalt;
  2059. term->alt_sblines = 0;
  2060. term->tabs = sresize(term->tabs, newcols, unsigned char);
  2061. {
  2062. int i;
  2063. for (i = (term->cols > 0 ? term->cols : 0); i < newcols; i++)
  2064. term->tabs[i] = (i % 8 == 0 ? true : false);
  2065. }
  2066. /* Check that the cursor positions are still valid. */
  2067. if (term->savecurs.y < 0)
  2068. term->savecurs.y = 0;
  2069. if (term->savecurs.y >= newrows)
  2070. term->savecurs.y = newrows - 1;
  2071. if (term->savecurs.x >= newcols)
  2072. term->savecurs.x = newcols - 1;
  2073. if (term->alt_savecurs.y < 0)
  2074. term->alt_savecurs.y = 0;
  2075. if (term->alt_savecurs.y >= newrows)
  2076. term->alt_savecurs.y = newrows - 1;
  2077. if (term->alt_savecurs.x >= newcols)
  2078. term->alt_savecurs.x = newcols - 1;
  2079. if (term->curs.y < 0)
  2080. term->curs.y = 0;
  2081. if (term->curs.y >= newrows)
  2082. term->curs.y = newrows - 1;
  2083. if (term->curs.x >= newcols)
  2084. term->curs.x = newcols - 1;
  2085. if (term->alt_y < 0)
  2086. term->alt_y = 0;
  2087. if (term->alt_y >= newrows)
  2088. term->alt_y = newrows - 1;
  2089. if (term->alt_x >= newcols)
  2090. term->alt_x = newcols - 1;
  2091. term->alt_x = term->alt_y = 0;
  2092. term->wrapnext = false;
  2093. term->alt_wnext = false;
  2094. term->rows = newrows;
  2095. term->cols = newcols;
  2096. term->savelines = newsavelines;
  2097. swap_screen(term, save_alt_which, false, false);
  2098. term->win_scrollbar_update_pending = true;
  2099. term_schedule_update(term);
  2100. if (term->backend)
  2101. backend_size(term->backend, term->cols, term->rows);
  2102. }
  2103. void term_resize_request_completed(Terminal *term)
  2104. {
  2105. assert(term->win_resize_pending == WIN_RESIZE_AWAIT_REPLY);
  2106. term->win_resize_pending = WIN_RESIZE_NO;
  2107. queue_toplevel_callback(term_out_cb, term);
  2108. }
  2109. /*
  2110. * Hand a backend to the terminal, so it can be notified of resizes.
  2111. */
  2112. void term_provide_backend(Terminal *term, Backend *backend)
  2113. {
  2114. term->backend = backend;
  2115. if (term->backend && term->cols > 0 && term->rows > 0)
  2116. backend_size(term->backend, term->cols, term->rows);
  2117. }
  2118. /* Find the bottom line on the screen that has any content.
  2119. * If only the top line has content, returns 0.
  2120. * If no lines have content, return -1.
  2121. */
  2122. static int find_last_nonempty_line(Terminal *term, tree234 *screen)
  2123. {
  2124. int i;
  2125. for (i = count234(screen) - 1; i >= 0; i--) {
  2126. termline *line = index234(screen, i);
  2127. int j;
  2128. for (j = 0; j < line->cols; j++)
  2129. if (!termchars_equal(&line->chars[j], &term->erase_char))
  2130. break;
  2131. if (j != line->cols) break;
  2132. }
  2133. return i;
  2134. }
  2135. /*
  2136. * Swap screens. If `reset' is true and we have been asked to
  2137. * switch to the alternate screen, we must bring most of its
  2138. * configuration from the main screen and erase the contents of the
  2139. * alternate screen completely. (This is even true if we're already
  2140. * on it! Blame xterm.)
  2141. */
  2142. static void swap_screen(Terminal *term, int which,
  2143. bool reset, bool keep_cur_pos)
  2144. {
  2145. int t;
  2146. bool bt;
  2147. pos tp;
  2148. truecolour ttc;
  2149. tree234 *ttr;
  2150. if (!which)
  2151. reset = false; /* do no weird resetting if which==0 */
  2152. if (which != term->alt_which) {
  2153. if (term->erase_to_scrollback && term->alt_screen &&
  2154. term->alt_which && term->disptop < 0) {
  2155. /*
  2156. * We're swapping away from the alternate screen, so some
  2157. * lines are about to vanish from the virtual scrollback.
  2158. * Adjust disptop by that much, so that (if we're not
  2159. * resetting the scrollback anyway on a display event) the
  2160. * current scroll position still ends up pointing at the
  2161. * same text.
  2162. */
  2163. term->disptop += term->alt_sblines;
  2164. if (term->disptop > 0)
  2165. term->disptop = 0;
  2166. }
  2167. term->alt_which = which;
  2168. ttr = term->alt_screen;
  2169. term->alt_screen = term->screen;
  2170. term->screen = ttr;
  2171. term->alt_sblines = (
  2172. term->alt_screen ?
  2173. find_last_nonempty_line(term, term->alt_screen) + 1 : 0);
  2174. t = term->curs.x;
  2175. if (!reset && !keep_cur_pos)
  2176. term->curs.x = term->alt_x;
  2177. term->alt_x = t;
  2178. t = term->curs.y;
  2179. if (!reset && !keep_cur_pos)
  2180. term->curs.y = term->alt_y;
  2181. term->alt_y = t;
  2182. t = term->marg_t;
  2183. if (!reset) term->marg_t = term->alt_t;
  2184. term->alt_t = t;
  2185. t = term->marg_b;
  2186. if (!reset) term->marg_b = term->alt_b;
  2187. term->alt_b = t;
  2188. bt = term->dec_om;
  2189. if (!reset) term->dec_om = term->alt_om;
  2190. term->alt_om = bt;
  2191. bt = term->wrap;
  2192. if (!reset) term->wrap = term->alt_wrap;
  2193. term->alt_wrap = bt;
  2194. bt = term->wrapnext;
  2195. if (!reset) term->wrapnext = term->alt_wnext;
  2196. term->alt_wnext = bt;
  2197. bt = term->insert;
  2198. if (!reset) term->insert = term->alt_ins;
  2199. term->alt_ins = bt;
  2200. t = term->cset;
  2201. if (!reset) term->cset = term->alt_cset;
  2202. term->alt_cset = t;
  2203. bt = term->utf;
  2204. if (!reset) term->utf = term->alt_utf;
  2205. term->alt_utf = bt;
  2206. t = term->sco_acs;
  2207. if (!reset) term->sco_acs = term->alt_sco_acs;
  2208. term->alt_sco_acs = t;
  2209. tp = term->savecurs;
  2210. if (!reset)
  2211. term->savecurs = term->alt_savecurs;
  2212. term->alt_savecurs = tp;
  2213. t = term->save_cset;
  2214. if (!reset)
  2215. term->save_cset = term->alt_save_cset;
  2216. term->alt_save_cset = t;
  2217. t = term->save_csattr;
  2218. if (!reset)
  2219. term->save_csattr = term->alt_save_csattr;
  2220. term->alt_save_csattr = t;
  2221. t = term->save_attr;
  2222. if (!reset)
  2223. term->save_attr = term->alt_save_attr;
  2224. term->alt_save_attr = t;
  2225. ttc = term->save_truecolour;
  2226. if (!reset)
  2227. term->save_truecolour = term->alt_save_truecolour;
  2228. term->alt_save_truecolour = ttc;
  2229. bt = term->save_utf;
  2230. if (!reset)
  2231. term->save_utf = term->alt_save_utf;
  2232. term->alt_save_utf = bt;
  2233. bt = term->save_wnext;
  2234. if (!reset)
  2235. term->save_wnext = term->alt_save_wnext;
  2236. term->alt_save_wnext = bt;
  2237. t = term->save_sco_acs;
  2238. if (!reset)
  2239. term->save_sco_acs = term->alt_save_sco_acs;
  2240. term->alt_save_sco_acs = t;
  2241. if (term->erase_to_scrollback && term->alt_screen &&
  2242. term->alt_which && term->disptop < 0) {
  2243. /*
  2244. * Inverse of the adjustment at the top of this function.
  2245. * This time, we're swapping _to_ the alternate screen, so
  2246. * some lines are about to _appear_ in the virtual
  2247. * scrollback, and we adjust disptop in the other
  2248. * direction.
  2249. *
  2250. * Both these adjustments depend on the value stored in
  2251. * term->alt_sblines while the alt screen is selected,
  2252. * which is why we had to do one _before_ switching away
  2253. * from it and the other _after_ switching to it.
  2254. */
  2255. term->disptop -= term->alt_sblines;
  2256. int limit = -sblines(term);
  2257. if (term->disptop < limit)
  2258. term->disptop = limit;
  2259. }
  2260. }
  2261. if (reset && term->screen) {
  2262. /*
  2263. * Yes, this _is_ supposed to honour background-colour-erase.
  2264. */
  2265. erase_lots(term, false, true, true);
  2266. }
  2267. seen_disp_event(term);
  2268. }
  2269. /*
  2270. * Update the scroll bar.
  2271. */
  2272. static void update_sbar(Terminal *term)
  2273. {
  2274. int nscroll = sblines(term);
  2275. win_set_scrollbar(term->win, nscroll + term->rows,
  2276. nscroll + term->disptop, term->rows);
  2277. }
  2278. /*
  2279. * Check whether the region bounded by the two pointers intersects
  2280. * the scroll region, and de-select the on-screen selection if so.
  2281. */
  2282. static void check_selection(Terminal *term, pos from, pos to)
  2283. {
  2284. if (poslt(from, term->selend) && poslt(term->selstart, to))
  2285. deselect(term);
  2286. }
  2287. static void clear_line(Terminal *term, termline *line)
  2288. {
  2289. resizeline(term, line, term->cols);
  2290. for (int i = 0; i < term->cols; i++)
  2291. copy_termchar(line, i, &term->erase_char);
  2292. line->lattr = LATTR_NORM;
  2293. }
  2294. static void check_trust_status(Terminal *term, termline *line)
  2295. {
  2296. if (line->trusted != term->trusted) {
  2297. /*
  2298. * If we're displaying trusted output on a previously
  2299. * untrusted line, or vice versa, we need to switch the
  2300. * 'trusted' attribute on this terminal line, and also clear
  2301. * all its previous contents.
  2302. */
  2303. clear_line(term, line);
  2304. line->trusted = term->trusted;
  2305. }
  2306. }
  2307. /*
  2308. * Scroll the screen. (`lines' is +ve for scrolling forward, -ve
  2309. * for backward.) `sb' is true if the scrolling is permitted to
  2310. * affect the scrollback buffer.
  2311. */
  2312. static void scroll(Terminal *term, int topline, int botline,
  2313. int lines, bool sb)
  2314. {
  2315. termline *line;
  2316. int seltop, scrollwinsize;
  2317. if (topline != 0 || term->alt_which != 0)
  2318. sb = false;
  2319. scrollwinsize = botline - topline + 1;
  2320. if (lines < 0) {
  2321. lines = -lines;
  2322. if (lines > scrollwinsize)
  2323. lines = scrollwinsize;
  2324. while (lines-- > 0) {
  2325. line = delpos234(term->screen, botline);
  2326. resizeline(term, line, term->cols);
  2327. clear_line(term, line);
  2328. addpos234(term->screen, line, topline);
  2329. if (term->selstart.y >= topline && term->selstart.y <= botline) {
  2330. term->selstart.y++;
  2331. if (term->selstart.y > botline) {
  2332. term->selstart.y = botline + 1;
  2333. term->selstart.x = 0;
  2334. }
  2335. }
  2336. if (term->selend.y >= topline && term->selend.y <= botline) {
  2337. term->selend.y++;
  2338. if (term->selend.y > botline) {
  2339. term->selend.y = botline + 1;
  2340. term->selend.x = 0;
  2341. }
  2342. }
  2343. }
  2344. } else {
  2345. if (lines > scrollwinsize)
  2346. lines = scrollwinsize;
  2347. while (lines-- > 0) {
  2348. line = delpos234(term->screen, topline);
  2349. #ifdef TERM_CC_DIAGS
  2350. cc_check(line);
  2351. #endif
  2352. if (sb && term->savelines > 0) {
  2353. int sblen = count234(term->scrollback);
  2354. /*
  2355. * We must add this line to the scrollback. We'll
  2356. * remove a line from the top of the scrollback if
  2357. * the scrollback is full.
  2358. */
  2359. if (sblen == term->savelines) {
  2360. compressed_scrollback_line *cline;
  2361. sblen--;
  2362. cline = delpos234(term->scrollback, 0);
  2363. free_compressed_line(cline);
  2364. } else
  2365. term->tempsblines += 1;
  2366. addpos234(term->scrollback, compressline_no_free(line), sblen);
  2367. /* now `line' itself can be reused as the bottom line */
  2368. /*
  2369. * If the user is currently looking at part of the
  2370. * scrollback, and they haven't enabled any options
  2371. * that are going to reset the scrollback as a
  2372. * result of this movement, then the chances are
  2373. * they'd like to keep looking at the same line. So
  2374. * we move their viewpoint at the same rate as the
  2375. * scroll, at least until their viewpoint hits the
  2376. * top end of the scrollback buffer, at which point
  2377. * we don't have the choice any more.
  2378. *
  2379. * Thanks to Jan Holmen Holsten for the idea and
  2380. * initial implementation.
  2381. */
  2382. if (term->disptop > -term->savelines && term->disptop < 0)
  2383. term->disptop--;
  2384. /*
  2385. * We've just modified the data that the terminal's
  2386. * scrollbar is based on, so remember to update it.
  2387. */
  2388. term->win_scrollbar_update_pending = true;
  2389. }
  2390. resizeline(term, line, term->cols);
  2391. clear_line(term, line);
  2392. line->trusted = false;
  2393. addpos234(term->screen, line, botline);
  2394. /*
  2395. * If the selection endpoints move into the scrollback,
  2396. * we keep them moving until they hit the top. However,
  2397. * of course, if the line _hasn't_ moved into the
  2398. * scrollback then we don't do this, and cut them off
  2399. * at the top of the scroll region.
  2400. *
  2401. * This applies to selstart and selend (for an existing
  2402. * selection), and also selanchor (for one being
  2403. * selected as we speak).
  2404. */
  2405. seltop = sb ? -term->savelines : topline;
  2406. if (term->selstate != NO_SELECTION) {
  2407. if (term->selstart.y >= seltop &&
  2408. term->selstart.y <= botline) {
  2409. term->selstart.y--;
  2410. if (term->selstart.y < seltop) {
  2411. term->selstart.y = seltop;
  2412. term->selstart.x = 0;
  2413. }
  2414. }
  2415. if (term->selend.y >= seltop && term->selend.y <= botline) {
  2416. term->selend.y--;
  2417. if (term->selend.y < seltop) {
  2418. term->selend.y = seltop;
  2419. term->selend.x = 0;
  2420. }
  2421. }
  2422. if (term->selanchor.y >= seltop &&
  2423. term->selanchor.y <= botline) {
  2424. term->selanchor.y--;
  2425. if (term->selanchor.y < seltop) {
  2426. term->selanchor.y = seltop;
  2427. term->selanchor.x = 0;
  2428. }
  2429. }
  2430. }
  2431. }
  2432. }
  2433. seen_disp_event(term);
  2434. }
  2435. /*
  2436. * Move the cursor to a given position, clipping at boundaries. We
  2437. * may or may not want to clip at the scroll margin: marg_clip is 0
  2438. * not to, 1 to disallow _passing_ the margins, and 2 to disallow
  2439. * even _being_ outside the margins.
  2440. */
  2441. static void move(Terminal *term, int x, int y, int marg_clip)
  2442. {
  2443. if (x < 0)
  2444. x = 0;
  2445. if (x >= term->cols)
  2446. x = term->cols - 1;
  2447. if (marg_clip) {
  2448. if ((term->curs.y >= term->marg_t || marg_clip == 2) &&
  2449. y < term->marg_t)
  2450. y = term->marg_t;
  2451. if ((term->curs.y <= term->marg_b || marg_clip == 2) &&
  2452. y > term->marg_b)
  2453. y = term->marg_b;
  2454. }
  2455. if (y < 0)
  2456. y = 0;
  2457. if (y >= term->rows)
  2458. y = term->rows - 1;
  2459. term->curs.x = x;
  2460. term->curs.y = y;
  2461. term->wrapnext = false;
  2462. seen_disp_event(term);
  2463. }
  2464. /*
  2465. * Save or restore the cursor and SGR mode.
  2466. */
  2467. static void save_cursor(Terminal *term, bool save)
  2468. {
  2469. if (save) {
  2470. term->savecurs = term->curs;
  2471. term->save_attr = term->curr_attr;
  2472. term->save_truecolour = term->curr_truecolour;
  2473. term->save_cset = term->cset;
  2474. term->save_utf = term->utf;
  2475. term->save_wnext = term->wrapnext;
  2476. term->save_csattr = term->cset_attr[term->cset];
  2477. term->save_sco_acs = term->sco_acs;
  2478. } else {
  2479. term->curs = term->savecurs;
  2480. /* Make sure the window hasn't shrunk since the save */
  2481. if (term->curs.x >= term->cols)
  2482. term->curs.x = term->cols - 1;
  2483. if (term->curs.y >= term->rows)
  2484. term->curs.y = term->rows - 1;
  2485. term->curr_attr = term->save_attr;
  2486. term->curr_truecolour = term->save_truecolour;
  2487. term->cset = term->save_cset;
  2488. term->utf = term->save_utf;
  2489. term->wrapnext = term->save_wnext;
  2490. /*
  2491. * wrapnext might reset to False if the x position is no
  2492. * longer at the rightmost edge.
  2493. */
  2494. if (term->wrapnext && term->curs.x < term->cols-1)
  2495. term->wrapnext = false;
  2496. term->cset_attr[term->cset] = term->save_csattr;
  2497. term->sco_acs = term->save_sco_acs;
  2498. set_erase_char(term);
  2499. seen_disp_event(term);
  2500. }
  2501. }
  2502. /*
  2503. * This function is called before doing _anything_ which affects
  2504. * only part of a line of text. It is used to mark the boundary
  2505. * between two character positions, and it indicates that some sort
  2506. * of effect is going to happen on only one side of that boundary.
  2507. *
  2508. * The effect of this function is to check whether a CJK
  2509. * double-width character is straddling the boundary, and to remove
  2510. * it and replace it with two spaces if so. (Of course, one or
  2511. * other of those spaces is then likely to be replaced with
  2512. * something else again, as a result of whatever happens next.)
  2513. *
  2514. * Also, if the boundary is at the right-hand _edge_ of the screen,
  2515. * it implies something deliberate is being done to the rightmost
  2516. * column position; hence we must clear LATTR_WRAPPED2.
  2517. *
  2518. * The input to the function is the coordinates of the _second_
  2519. * character of the pair.
  2520. */
  2521. static void check_boundary(Terminal *term, int x, int y)
  2522. {
  2523. termline *ldata;
  2524. /* Validate input coordinates, just in case. */
  2525. if (x <= 0 || x > term->cols)
  2526. return;
  2527. ldata = scrlineptr(y);
  2528. check_trust_status(term, ldata);
  2529. check_line_size(term, ldata);
  2530. if (x == term->cols) {
  2531. ldata->lattr &= ~LATTR_WRAPPED2;
  2532. } else {
  2533. if (ldata->chars[x].chr == UCSWIDE) {
  2534. clear_cc(ldata, x-1);
  2535. clear_cc(ldata, x);
  2536. ldata->chars[x-1].chr = ' ' | CSET_ASCII;
  2537. ldata->chars[x] = ldata->chars[x-1];
  2538. }
  2539. }
  2540. }
  2541. /*
  2542. * Erase a large portion of the screen: the whole screen, or the
  2543. * whole line, or parts thereof.
  2544. */
  2545. static void erase_lots(Terminal *term,
  2546. bool line_only, bool from_begin, bool to_end)
  2547. {
  2548. pos start, end;
  2549. bool erase_lattr;
  2550. bool erasing_lines_from_top = false;
  2551. if (line_only) {
  2552. start.y = term->curs.y;
  2553. start.x = 0;
  2554. end.y = term->curs.y + 1;
  2555. end.x = 0;
  2556. erase_lattr = false;
  2557. } else {
  2558. start.y = 0;
  2559. start.x = 0;
  2560. end.y = term->rows;
  2561. end.x = 0;
  2562. erase_lattr = true;
  2563. }
  2564. /* This is the endpoint of the clearing operation that is not
  2565. * either the start or end of the line / screen. */
  2566. pos boundary = term->curs;
  2567. if (!from_begin) {
  2568. /*
  2569. * If we're erasing from the current char to the end of
  2570. * line/screen, then we take account of wrapnext, so as to
  2571. * maintain the invariant that writing a printing character
  2572. * followed by ESC[K should not overwrite the character you
  2573. * _just wrote_. That is, when wrapnext says the cursor is
  2574. * 'logically' at the very rightmost edge of the screen
  2575. * instead of just before the last printing char, ESC[K should
  2576. * do nothing at all, and ESC[J should clear the next line but
  2577. * leave this one unchanged.
  2578. *
  2579. * This adjusted position will also be the position we use for
  2580. * check_boundary (i.e. the thing we ensure isn't in the
  2581. * middle of a double-width printing char).
  2582. */
  2583. if (term->wrapnext)
  2584. incpos(boundary);
  2585. start = boundary;
  2586. }
  2587. if (!to_end) {
  2588. /*
  2589. * If we're erasing from the start of (at least) the line _to_
  2590. * the current position, then that is taken to mean 'inclusive
  2591. * of the cell under the cursor', which means we don't
  2592. * consider wrapnext at all: whether it's set or not, we still
  2593. * clear the cell under the cursor.
  2594. *
  2595. * Again, that incremented boundary position is where we
  2596. * should be careful of a straddling wide character.
  2597. */
  2598. incpos(boundary);
  2599. end = boundary;
  2600. }
  2601. if (!from_begin || !to_end)
  2602. check_boundary(term, boundary.x, boundary.y);
  2603. check_selection(term, start, end);
  2604. /* Clear screen also forces a full window redraw, just in case. */
  2605. if (start.y == 0 && start.x == 0 && end.y == term->rows)
  2606. term_invalidate(term);
  2607. /* Lines scrolled away shouldn't be brought back on if the terminal
  2608. * resizes. */
  2609. if (start.y == 0 && start.x == 0 && end.x == 0 && erase_lattr)
  2610. erasing_lines_from_top = true;
  2611. if (term->erase_to_scrollback && erasing_lines_from_top) {
  2612. /* If it's a whole number of lines, starting at the top, and
  2613. * we're fully erasing them, erase by scrolling and keep the
  2614. * lines in the scrollback. */
  2615. int scrolllines = end.y;
  2616. if (end.y == term->rows) {
  2617. /* Shrink until we find a non-empty row.*/
  2618. scrolllines = find_last_nonempty_line(term, term->screen) + 1;
  2619. }
  2620. if (scrolllines > 0)
  2621. scroll(term, 0, scrolllines - 1, scrolllines, true);
  2622. } else {
  2623. termline *ldata = scrlineptr(start.y);
  2624. check_trust_status(term, ldata);
  2625. while (poslt(start, end)) {
  2626. check_line_size(term, ldata);
  2627. if (start.x == term->cols) {
  2628. if (!erase_lattr)
  2629. ldata->lattr &= ~(LATTR_WRAPPED | LATTR_WRAPPED2);
  2630. else
  2631. ldata->lattr = LATTR_NORM;
  2632. } else {
  2633. copy_termchar(ldata, start.x, &term->erase_char);
  2634. }
  2635. if (incpos(start) && start.y < term->rows) {
  2636. ldata = scrlineptr(start.y);
  2637. check_trust_status(term, ldata);
  2638. }
  2639. }
  2640. }
  2641. /* After an erase of lines from the top of the screen, we shouldn't
  2642. * bring the lines back again if the terminal enlarges (since the user or
  2643. * application has explicitly thrown them away). */
  2644. if (erasing_lines_from_top && !(term->alt_which))
  2645. term->tempsblines = 0;
  2646. seen_disp_event(term);
  2647. }
  2648. /*
  2649. * Insert or delete characters within the current line. n is +ve if
  2650. * insertion is desired, and -ve for deletion.
  2651. */
  2652. static void insch(Terminal *term, int n)
  2653. {
  2654. int dir = (n < 0 ? -1 : +1);
  2655. int m, j;
  2656. pos eol;
  2657. termline *ldata;
  2658. n = (n < 0 ? -n : n);
  2659. if (n > term->cols - term->curs.x)
  2660. n = term->cols - term->curs.x;
  2661. m = term->cols - term->curs.x - n;
  2662. /*
  2663. * We must de-highlight the selection if it overlaps any part of
  2664. * the region affected by this operation, i.e. the region from the
  2665. * current cursor position to end-of-line, _unless_ the entirety
  2666. * of the selection is going to be moved to the left or right by
  2667. * this operation but otherwise unchanged, in which case we can
  2668. * simply move the highlight with the text.
  2669. */
  2670. eol.y = term->curs.y;
  2671. eol.x = term->cols;
  2672. if (poslt(term->curs, term->selend) && poslt(term->selstart, eol)) {
  2673. pos okstart = term->curs;
  2674. pos okend = eol;
  2675. if (dir > 0) {
  2676. /* Insertion: n characters at EOL will be splatted. */
  2677. okend.x -= n;
  2678. } else {
  2679. /* Deletion: n characters at cursor position will be splatted. */
  2680. okstart.x += n;
  2681. }
  2682. if (posle(okstart, term->selstart) && posle(term->selend, okend)) {
  2683. /* Selection is contained entirely in the interval
  2684. * [okstart,okend), so we need only adjust the selection
  2685. * bounds. */
  2686. term->selstart.x += dir * n;
  2687. term->selend.x += dir * n;
  2688. assert(term->selstart.x >= term->curs.x);
  2689. assert(term->selstart.x < term->cols);
  2690. assert(term->selend.x > term->curs.x);
  2691. assert(term->selend.x <= term->cols);
  2692. } else {
  2693. /* Selection is not wholly contained in that interval, so
  2694. * we must unhighlight it. */
  2695. deselect(term);
  2696. }
  2697. }
  2698. check_boundary(term, term->curs.x, term->curs.y);
  2699. if (dir < 0)
  2700. check_boundary(term, term->curs.x + n, term->curs.y);
  2701. ldata = scrlineptr(term->curs.y);
  2702. check_trust_status(term, ldata);
  2703. if (dir < 0) {
  2704. for (j = 0; j < m; j++)
  2705. move_termchar(ldata,
  2706. ldata->chars + term->curs.x + j,
  2707. ldata->chars + term->curs.x + j + n);
  2708. while (n--)
  2709. copy_termchar(ldata, term->curs.x + m++, &term->erase_char);
  2710. } else {
  2711. for (j = m; j-- ;)
  2712. move_termchar(ldata,
  2713. ldata->chars + term->curs.x + j + n,
  2714. ldata->chars + term->curs.x + j);
  2715. while (n--)
  2716. copy_termchar(ldata, term->curs.x + n, &term->erase_char);
  2717. }
  2718. }
  2719. static void term_update_raw_mouse_mode(Terminal *term)
  2720. {
  2721. bool want_raw = (term->xterm_mouse != 0 && !term->xterm_mouse_forbidden);
  2722. win_set_raw_mouse_mode(term->win, want_raw);
  2723. term->win_pointer_shape_pending = true;
  2724. term->win_pointer_shape_raw = want_raw;
  2725. term_schedule_update(term);
  2726. }
  2727. static void term_request_resize(Terminal *term, int cols, int rows)
  2728. {
  2729. if (term->cols == cols && term->rows == rows)
  2730. return; /* don't need to do anything */
  2731. term->win_resize_pending = WIN_RESIZE_NEED_SEND;
  2732. term->win_resize_pending_w = cols;
  2733. term->win_resize_pending_h = rows;
  2734. term_schedule_update(term);
  2735. }
  2736. /*
  2737. * Toggle terminal mode `mode' to state `state'. (`query' indicates
  2738. * whether the mode is a DEC private one or a normal one.)
  2739. */
  2740. static void toggle_mode(Terminal *term, int mode, int query, bool state)
  2741. {
  2742. if (query == 1) {
  2743. switch (mode) {
  2744. case 1: /* DECCKM: application cursor keys */
  2745. term->app_cursor_keys = state;
  2746. break;
  2747. case 2: /* DECANM: VT52 mode */
  2748. term->vt52_mode = !state;
  2749. if (term->vt52_mode) {
  2750. term->blink_is_real = false;
  2751. term->vt52_bold = false;
  2752. } else {
  2753. term->blink_is_real = term->blinktext;
  2754. }
  2755. term_schedule_tblink(term);
  2756. break;
  2757. case 3: /* DECCOLM: 80/132 columns */
  2758. deselect(term);
  2759. if (!term->no_remote_resize)
  2760. term_request_resize(term, state ? 132 : 80, term->rows);
  2761. term->reset_132 = state;
  2762. term->alt_t = term->marg_t = 0;
  2763. term->alt_b = term->marg_b = term->rows - 1;
  2764. move(term, 0, 0, 0);
  2765. erase_lots(term, false, true, true);
  2766. break;
  2767. case 5: /* DECSCNM: reverse video */
  2768. /*
  2769. * Toggle reverse video. If we receive an OFF within the
  2770. * visual bell timeout period after an ON, we trigger an
  2771. * effective visual bell, so that ESC[?5hESC[?5l will
  2772. * always be an actually _visible_ visual bell.
  2773. */
  2774. if (term->rvideo && !state) {
  2775. /* This is an OFF, so set up a vbell */
  2776. term_schedule_vbell(term, true, term->rvbell_startpoint);
  2777. } else if (!term->rvideo && state) {
  2778. /* This is an ON, so we notice the time and save it. */
  2779. term->rvbell_startpoint = GETTICKCOUNT();
  2780. }
  2781. term->rvideo = state;
  2782. seen_disp_event(term);
  2783. break;
  2784. case 6: /* DECOM: DEC origin mode */
  2785. term->dec_om = state;
  2786. break;
  2787. case 7: /* DECAWM: auto wrap */
  2788. term->wrap = state;
  2789. if (!term->wrap)
  2790. term->wrapnext = false;
  2791. break;
  2792. case 8: /* DECARM: auto key repeat */
  2793. term->repeat_off = !state;
  2794. break;
  2795. case 25: /* DECTCEM: enable/disable cursor */
  2796. compatibility2(OTHER, VT220);
  2797. term->cursor_on = state;
  2798. seen_disp_event(term);
  2799. break;
  2800. case 47: /* alternate screen */
  2801. compatibility(OTHER);
  2802. deselect(term);
  2803. swap_screen(term, term->no_alt_screen ? 0 : state, false, false);
  2804. if (term->scroll_on_disp)
  2805. term->disptop = 0;
  2806. break;
  2807. case 1000: /* xterm mouse 1 (normal) */
  2808. term->xterm_mouse = state ? 1 : 0;
  2809. term_update_raw_mouse_mode(term);
  2810. break;
  2811. case 1002: /* xterm mouse 2 (inc. button drags) */
  2812. term->xterm_mouse = state ? 2 : 0;
  2813. term_update_raw_mouse_mode(term);
  2814. break;
  2815. case 1003: /* xterm mouse any-event tracking */
  2816. term->xterm_mouse = state ? 3 : 0;
  2817. term_update_raw_mouse_mode(term);
  2818. break;
  2819. case 1006: /* xterm extended mouse */
  2820. term->xterm_extended_mouse = state;
  2821. break;
  2822. case 1015: /* urxvt extended mouse */
  2823. term->urxvt_extended_mouse = state;
  2824. break;
  2825. case 1047: /* alternate screen */
  2826. compatibility(OTHER);
  2827. deselect(term);
  2828. swap_screen(term, term->no_alt_screen ? 0 : state, true, true);
  2829. if (term->scroll_on_disp)
  2830. term->disptop = 0;
  2831. break;
  2832. case 1048: /* save/restore cursor */
  2833. if (!term->no_alt_screen)
  2834. save_cursor(term, state);
  2835. if (!state) seen_disp_event(term);
  2836. break;
  2837. case 1049: /* cursor & alternate screen */
  2838. if (state && !term->no_alt_screen)
  2839. save_cursor(term, state);
  2840. if (!state) seen_disp_event(term);
  2841. compatibility(OTHER);
  2842. deselect(term);
  2843. swap_screen(term, term->no_alt_screen ? 0 : state, true, false);
  2844. if (!state && !term->no_alt_screen)
  2845. save_cursor(term, state);
  2846. if (term->scroll_on_disp)
  2847. term->disptop = 0;
  2848. break;
  2849. case 2004: /* xterm bracketed paste */
  2850. term->bracketed_paste = state ? true : false;
  2851. break;
  2852. }
  2853. } else if (query == 0) {
  2854. switch (mode) {
  2855. case 4: /* IRM: set insert mode */
  2856. compatibility(VT102);
  2857. term->insert = state;
  2858. break;
  2859. case 12: /* SRM: set echo mode */
  2860. term->srm_echo = !state;
  2861. break;
  2862. case 20: /* LNM: Return sends ... */
  2863. term->cr_lf_return = state;
  2864. break;
  2865. case 34: /* WYULCURM: Make cursor BIG */
  2866. compatibility2(OTHER, VT220);
  2867. term->big_cursor = !state;
  2868. }
  2869. }
  2870. }
  2871. /*
  2872. * Process an OSC sequence: set window title or icon name.
  2873. */
  2874. static void do_osc(Terminal *term)
  2875. {
  2876. if (term->osc_is_apc) {
  2877. /* This OSC was really an APC, and we don't support that
  2878. * sequence at all. We only recognise it in order to ignore it
  2879. * and filter it out of input. */
  2880. return;
  2881. }
  2882. if (term->osc_w) {
  2883. while (term->osc_strlen--)
  2884. term->wordness[(unsigned char)term->osc_string[term->osc_strlen]] =
  2885. term->esc_args[0];
  2886. } else {
  2887. term->osc_string[term->osc_strlen] = '\0';
  2888. switch (term->esc_args[0]) {
  2889. case 0:
  2890. case 1:
  2891. if (!term->no_remote_wintitle) {
  2892. sfree(term->icon_title);
  2893. term->icon_title = dupstr(term->osc_string);
  2894. term->icontitle_codepage = term->ucsdata->line_codepage;
  2895. term->win_icon_title_pending = true;
  2896. term_schedule_update(term);
  2897. }
  2898. if (term->esc_args[0] == 1)
  2899. break;
  2900. /* fall through: parameter 0 means set both */
  2901. case 2:
  2902. case 21:
  2903. if (!term->no_remote_wintitle) {
  2904. sfree(term->window_title);
  2905. term->window_title = dupstr(term->osc_string);
  2906. term->wintitle_codepage = term->ucsdata->line_codepage;
  2907. term->win_title_pending = true;
  2908. term_schedule_update(term);
  2909. }
  2910. break;
  2911. case 4:
  2912. if (term->ldisc && !strcmp(term->osc_string, "?")) {
  2913. unsigned index = term->esc_args[1];
  2914. if (index < OSC4_NCOLOURS) {
  2915. rgb colour = term->palette[index];
  2916. char *reply_buf = dupprintf(
  2917. "\033]4;%u;rgb:%04x/%04x/%04x\007", index,
  2918. (unsigned)colour.r * 0x0101,
  2919. (unsigned)colour.g * 0x0101,
  2920. (unsigned)colour.b * 0x0101);
  2921. ldisc_send(term->ldisc, reply_buf, strlen(reply_buf),
  2922. false);
  2923. sfree(reply_buf);
  2924. }
  2925. }
  2926. break;
  2927. }
  2928. }
  2929. }
  2930. /*
  2931. * ANSI printing routines.
  2932. */
  2933. static void term_print_setup(Terminal *term, char *printer)
  2934. {
  2935. bufchain_clear(&term->printer_buf);
  2936. term->print_job = printer_start_job(printer);
  2937. }
  2938. static void term_print_flush(Terminal *term)
  2939. {
  2940. size_t size;
  2941. while ((size = bufchain_size(&term->printer_buf)) > 5) {
  2942. ptrlen data = bufchain_prefix(&term->printer_buf);
  2943. if (data.len > size-5)
  2944. data.len = size-5;
  2945. printer_job_data(term->print_job, data.ptr, data.len);
  2946. bufchain_consume(&term->printer_buf, data.len);
  2947. }
  2948. }
  2949. static void term_print_finish(Terminal *term)
  2950. {
  2951. size_t size;
  2952. char c;
  2953. if (!term->printing && !term->only_printing)
  2954. return; /* we need do nothing */
  2955. term_print_flush(term);
  2956. while ((size = bufchain_size(&term->printer_buf)) > 0) {
  2957. ptrlen data = bufchain_prefix(&term->printer_buf);
  2958. c = *(char *)data.ptr;
  2959. if (c == '\033' || c == '\233') {
  2960. bufchain_consume(&term->printer_buf, size);
  2961. break;
  2962. } else {
  2963. printer_job_data(term->print_job, &c, 1);
  2964. bufchain_consume(&term->printer_buf, 1);
  2965. }
  2966. }
  2967. printer_finish_job(term->print_job);
  2968. term->print_job = NULL;
  2969. term->printing = term->only_printing = false;
  2970. }
  2971. static void term_display_graphic_char(Terminal *term, unsigned long c)
  2972. {
  2973. termline *cline = scrlineptr(term->curs.y);
  2974. int width = 0;
  2975. if (DIRECT_CHAR(c))
  2976. width = 1;
  2977. if (!width)
  2978. width = term_char_width(term, c);
  2979. if (term->wrapnext && term->wrap && width > 0) {
  2980. cline->lattr |= LATTR_WRAPPED;
  2981. if (term->curs.y == term->marg_b)
  2982. scroll(term, term->marg_t, term->marg_b, 1, true);
  2983. else if (term->curs.y < term->rows - 1)
  2984. term->curs.y++;
  2985. term->curs.x = 0;
  2986. term->wrapnext = false;
  2987. cline = scrlineptr(term->curs.y);
  2988. }
  2989. if (term->insert && width > 0)
  2990. insch(term, width);
  2991. if (term->selstate != NO_SELECTION) {
  2992. pos cursplus = term->curs;
  2993. incpos(cursplus);
  2994. check_selection(term, term->curs, cursplus);
  2995. }
  2996. if (((c & CSET_MASK) == CSET_ASCII ||
  2997. (c & CSET_MASK) == 0) && term->logctx)
  2998. logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);
  2999. check_trust_status(term, cline);
  3000. int linecols = term->cols;
  3001. if (cline->trusted)
  3002. linecols -= TRUST_SIGIL_WIDTH;
  3003. /*
  3004. * Before we switch on the character width, do a preliminary check for
  3005. * cases where we might have no room at all to display a double-width
  3006. * character. Our fallback is to substitute REPLACEMENT CHARACTER,
  3007. * which is single-width, and it's easiest to do that _before_ having
  3008. * to 'goto' from one switch case to another.
  3009. */
  3010. if (width == 2 && term->curs.x >= linecols-1) {
  3011. /*
  3012. * If we're in wrapping mode and the terminal is at least 2 cells
  3013. * wide, it's OK, we have a fallback. But otherwise, substitute.
  3014. */
  3015. if (linecols < 2 || !term->wrap) {
  3016. width = 1;
  3017. c = 0xFFFD;
  3018. }
  3019. }
  3020. switch (width) {
  3021. case 2:
  3022. /*
  3023. * If we're about to display a double-width character starting in
  3024. * the rightmost column (and we're in wrapping mode - the other
  3025. * case was disposed of above), then we do something special
  3026. * instead. We must print a space in the last column of the screen,
  3027. * then wrap; and we also set LATTR_WRAPPED2 which instructs
  3028. * subsequent cut-and-pasting not only to splice this line to the
  3029. * one after it, but to ignore the space in the last character
  3030. * position as well. (Because what was actually output to the
  3031. * terminal was presumably just a sequence of CJK characters, and
  3032. * we don't want a space to be pasted in the middle of those just
  3033. * because they had the misfortune to start in the wrong parity
  3034. * column. xterm concurs.)
  3035. */
  3036. check_boundary(term, term->curs.x, term->curs.y);
  3037. check_boundary(term, term->curs.x+2, term->curs.y);
  3038. if (term->curs.x >= linecols-1) {
  3039. assert(term->wrap); /* we handled the non-wrapping case above */
  3040. copy_termchar(cline, term->curs.x,
  3041. &term->erase_char);
  3042. cline->lattr |= LATTR_WRAPPED | LATTR_WRAPPED2;
  3043. if (term->curs.y == term->marg_b)
  3044. scroll(term, term->marg_t, term->marg_b,
  3045. 1, true);
  3046. else if (term->curs.y < term->rows - 1)
  3047. term->curs.y++;
  3048. term->curs.x = 0;
  3049. cline = scrlineptr(term->curs.y);
  3050. /* Now we must check_boundary again, of course. */
  3051. check_boundary(term, term->curs.x, term->curs.y);
  3052. check_boundary(term, term->curs.x+2, term->curs.y);
  3053. }
  3054. /* FULL-TERMCHAR */
  3055. clear_cc(cline, term->curs.x);
  3056. cline->chars[term->curs.x].chr = c;
  3057. cline->chars[term->curs.x].attr = term->curr_attr;
  3058. cline->chars[term->curs.x].truecolour =
  3059. term->curr_truecolour;
  3060. term->curs.x++;
  3061. /* FULL-TERMCHAR */
  3062. clear_cc(cline, term->curs.x);
  3063. cline->chars[term->curs.x].chr = UCSWIDE;
  3064. cline->chars[term->curs.x].attr = term->curr_attr;
  3065. cline->chars[term->curs.x].truecolour =
  3066. term->curr_truecolour;
  3067. break;
  3068. case 1:
  3069. check_boundary(term, term->curs.x, term->curs.y);
  3070. check_boundary(term, term->curs.x+1, term->curs.y);
  3071. /* FULL-TERMCHAR */
  3072. clear_cc(cline, term->curs.x);
  3073. cline->chars[term->curs.x].chr = c;
  3074. cline->chars[term->curs.x].attr = term->curr_attr;
  3075. cline->chars[term->curs.x].truecolour =
  3076. term->curr_truecolour;
  3077. break;
  3078. case 0:
  3079. if (term->curs.x > 0) {
  3080. int x = term->curs.x - 1;
  3081. /* If we're in wrapnext state, the character to combine
  3082. * with is _here_, not to our left. */
  3083. if (term->wrapnext)
  3084. x++;
  3085. /*
  3086. * If the previous character is UCSWIDE, back up another
  3087. * one.
  3088. */
  3089. if (cline->chars[x].chr == UCSWIDE) {
  3090. assert(x > 0);
  3091. x--;
  3092. }
  3093. add_cc(cline, x, c);
  3094. seen_disp_event(term);
  3095. }
  3096. return;
  3097. default:
  3098. return;
  3099. }
  3100. term->curs.x++;
  3101. if (term->curs.x >= linecols) {
  3102. term->curs.x = linecols - 1;
  3103. if (term->wrap) {
  3104. if (!term->vt52_mode) {
  3105. /* Set the wrapnext flag, so that the next character
  3106. * wraps, but this one doesn't. */
  3107. term->wrapnext = true;
  3108. } else {
  3109. /* VT52 mode expects simpler handling, and we just
  3110. * wrap straight away. */
  3111. cline->lattr |= LATTR_WRAPPED;
  3112. if (term->curs.y == term->marg_b)
  3113. scroll(term, term->marg_t, term->marg_b, 1, true);
  3114. else if (term->curs.y < term->rows - 1)
  3115. term->curs.y++;
  3116. term->curs.x = 0;
  3117. term->wrapnext = false;
  3118. }
  3119. }
  3120. }
  3121. seen_disp_event(term);
  3122. }
  3123. static strbuf *term_input_data_from_unicode(
  3124. Terminal *term, const wchar_t *widebuf, int len)
  3125. {
  3126. strbuf *buf = strbuf_new();
  3127. if (in_utf(term)) {
  3128. /*
  3129. * Translate input wide characters into UTF-8 to go in the
  3130. * terminal's input data queue.
  3131. */
  3132. for (int i = 0; i < len; i++) {
  3133. unsigned long ch = widebuf[i];
  3134. if (IS_SURROGATE(ch)) {
  3135. #ifdef PLATFORM_IS_UTF16
  3136. if (i+1 < len) {
  3137. unsigned long ch2 = widebuf[i+1];
  3138. if (IS_SURROGATE_PAIR(ch, ch2)) {
  3139. ch = FROM_SURROGATES(ch, ch2);
  3140. i++;
  3141. }
  3142. } else
  3143. #endif
  3144. {
  3145. /* Unrecognised UTF-16 sequence */
  3146. ch = '.';
  3147. }
  3148. }
  3149. put_utf8_char(buf, ch);
  3150. }
  3151. } else {
  3152. /*
  3153. * Call to the character-set subsystem to translate into
  3154. * whatever charset the terminal is currently configured in.
  3155. *
  3156. * Since the terminal doesn't currently support any multibyte
  3157. * character set other than UTF-8, we can assume here that
  3158. * there will be at most one output byte per input wchar_t.
  3159. * (But also we must allow space for the trailing NUL that
  3160. * wc_to_mb will write.)
  3161. */
  3162. char *bufptr = strbuf_append(buf, len + 1);
  3163. int rv;
  3164. rv = wc_to_mb(term->ucsdata->line_codepage, 0, widebuf, len,
  3165. bufptr, len + 1, NULL);
  3166. strbuf_shrink_to(buf, rv < 0 ? 0 : rv);
  3167. }
  3168. return buf;
  3169. }
  3170. static strbuf *term_input_data_from_charset(
  3171. Terminal *term, int codepage, const char *str, int len)
  3172. {
  3173. strbuf *buf;
  3174. if (codepage < 0) {
  3175. buf = strbuf_new();
  3176. put_data(buf, str, len);
  3177. } else {
  3178. int widesize = len * 2; /* allow for UTF-16 surrogates */
  3179. wchar_t *widebuf = snewn(widesize, wchar_t);
  3180. int widelen = mb_to_wc(codepage, 0, str, len, widebuf, widesize);
  3181. buf = term_input_data_from_unicode(term, widebuf, widelen);
  3182. sfree(widebuf);
  3183. }
  3184. return buf;
  3185. }
  3186. static inline void term_bracketed_paste_start(Terminal *term)
  3187. {
  3188. ptrlen seq = PTRLEN_LITERAL("\033[200~");
  3189. if (term->ldisc)
  3190. ldisc_send(term->ldisc, seq.ptr, seq.len, false);
  3191. term->bracketed_paste_active = true;
  3192. }
  3193. static inline void term_bracketed_paste_stop(Terminal *term)
  3194. {
  3195. if (!term->bracketed_paste_active)
  3196. return;
  3197. ptrlen seq = PTRLEN_LITERAL("\033[201~");
  3198. if (term->ldisc)
  3199. ldisc_send(term->ldisc, seq.ptr, seq.len, false);
  3200. term->bracketed_paste_active = false;
  3201. }
  3202. static inline void term_keyinput_internal(
  3203. Terminal *term, const void *buf, int len, bool interactive)
  3204. {
  3205. if (term->srm_echo) {
  3206. /*
  3207. * Implement the terminal-level local echo behaviour that
  3208. * ECMA-48 specifies when terminal mode 12 is configured off
  3209. * (ESC[12l). In this mode, data input to the terminal via the
  3210. * keyboard is also added to the output buffer. But this
  3211. * doesn't apply to escape sequences generated as session
  3212. * input _within_ the terminal, e.g. in response to terminal
  3213. * query sequences, or the bracketing sequences of bracketed
  3214. * paste mode. Those will be sent directly via
  3215. * ldisc_send(term->ldisc, ...) and won't go through this
  3216. * function.
  3217. */
  3218. /* Mimic the special case of negative length in ldisc_send */
  3219. int true_len = len >= 0 ? len : strlen(buf);
  3220. bufchain_add(&term->inbuf, buf, true_len);
  3221. term_added_data(term, false);
  3222. }
  3223. if (interactive)
  3224. term_bracketed_paste_stop(term);
  3225. if (term->ldisc)
  3226. ldisc_send(term->ldisc, buf, len, interactive);
  3227. term_seen_key_event(term);
  3228. }
  3229. unsigned long term_translate(
  3230. Terminal *term, struct term_utf8_decode *utf8, unsigned char c)
  3231. {
  3232. if (in_utf(term)) {
  3233. switch (utf8->state) {
  3234. case 0:
  3235. if (c < 0x80) {
  3236. /* UTF-8 must be stateless so we ignore iso2022. */
  3237. if (term->ucsdata->unitab_ctrl[c] != 0xFF) {
  3238. return term->ucsdata->unitab_ctrl[c];
  3239. } else if ((term->utf8linedraw) &&
  3240. (term->cset_attr[term->cset] == CSET_LINEDRW)) {
  3241. /* Linedraw characters are explicitly enabled */
  3242. return c | CSET_LINEDRW;
  3243. } else {
  3244. return c | CSET_ASCII;
  3245. }
  3246. } else if ((c & 0xe0) == 0xc0) {
  3247. utf8->size = utf8->state = 1;
  3248. utf8->chr = (c & 0x1f);
  3249. } else if ((c & 0xf0) == 0xe0) {
  3250. utf8->size = utf8->state = 2;
  3251. utf8->chr = (c & 0x0f);
  3252. } else if ((c & 0xf8) == 0xf0) {
  3253. utf8->size = utf8->state = 3;
  3254. utf8->chr = (c & 0x07);
  3255. } else if ((c & 0xfc) == 0xf8) {
  3256. utf8->size = utf8->state = 4;
  3257. utf8->chr = (c & 0x03);
  3258. } else if ((c & 0xfe) == 0xfc) {
  3259. utf8->size = utf8->state = 5;
  3260. utf8->chr = (c & 0x01);
  3261. } else {
  3262. return UCSINVALID;
  3263. }
  3264. return UCSINCOMPLETE;
  3265. case 1:
  3266. case 2:
  3267. case 3:
  3268. case 4:
  3269. case 5:
  3270. if ((c & 0xC0) != 0x80) {
  3271. utf8->state = 0;
  3272. return UCSTRUNCATED; /* caller will then give us the
  3273. * same byte again */
  3274. }
  3275. utf8->chr = (utf8->chr << 6) | (c & 0x3f);
  3276. if (--utf8->state)
  3277. return UCSINCOMPLETE;
  3278. unsigned long t = utf8->chr;
  3279. /* Is somebody trying to be evil! */
  3280. if (t < 0x80 ||
  3281. (t < 0x800 && utf8->size >= 2) ||
  3282. (t < 0x10000 && utf8->size >= 3) ||
  3283. (t < 0x200000 && utf8->size >= 4) ||
  3284. (t < 0x4000000 && utf8->size >= 5))
  3285. return UCSINVALID;
  3286. /* Unicode line separator and paragraph separator are CR-LF */
  3287. if (t == 0x2028 || t == 0x2029)
  3288. return 0x85;
  3289. /* High controls are probably a Baaad idea too. */
  3290. if (t < 0xA0)
  3291. return 0xFFFD;
  3292. /* The UTF-16 surrogates are not nice either. */
  3293. /* The standard give the option of decoding these:
  3294. * I don't want to! */
  3295. if (t >= 0xD800 && t < 0xE000)
  3296. return UCSINVALID;
  3297. /* ISO 10646 characters now limited to UTF-16 range. */
  3298. if (t > 0x10FFFF)
  3299. return UCSINVALID;
  3300. /* U+FEFF is best seen as a null. */
  3301. if (t == 0xFEFF)
  3302. return UCSINCOMPLETE;
  3303. /* But U+FFFE is an error. */
  3304. if (t == 0xFFFE || t == 0xFFFF)
  3305. return UCSINVALID;
  3306. return t;
  3307. }
  3308. } else if (term->sco_acs &&
  3309. (c!='\033' && c!='\012' && c!='\015' && c!='\b')) {
  3310. /* Are we in the nasty ACS mode? Note: no sco in utf mode. */
  3311. if (term->sco_acs == 2)
  3312. c |= 0x80;
  3313. return c | CSET_SCOACS;
  3314. } else {
  3315. switch (term->cset_attr[term->cset]) {
  3316. /*
  3317. * Linedraw characters are different from 'ESC ( B'
  3318. * only for a small range. For ones outside that
  3319. * range, make sure we use the same font as well as
  3320. * the same encoding.
  3321. */
  3322. case CSET_LINEDRW:
  3323. if (term->ucsdata->unitab_ctrl[c] != 0xFF)
  3324. return term->ucsdata->unitab_ctrl[c];
  3325. else
  3326. return c | CSET_LINEDRW;
  3327. break;
  3328. case CSET_GBCHR:
  3329. /* If UK-ASCII, make the '#' a LineDraw Pound */
  3330. if (c == '#')
  3331. return '}' | CSET_LINEDRW;
  3332. /* fall through */
  3333. case CSET_ASCII:
  3334. if (term->ucsdata->unitab_ctrl[c] != 0xFF)
  3335. return term->ucsdata->unitab_ctrl[c];
  3336. else
  3337. return c | CSET_ASCII;
  3338. break;
  3339. case CSET_SCOACS:
  3340. if (c >= ' ')
  3341. return c | CSET_SCOACS;
  3342. break;
  3343. }
  3344. }
  3345. return c;
  3346. }
  3347. /*
  3348. * Remove everything currently in `inbuf' and stick it up on the
  3349. * in-memory display. There's a big state machine in here to
  3350. * process escape sequences...
  3351. */
  3352. static void term_out(Terminal *term, bool called_from_term_data)
  3353. {
  3354. unsigned long c;
  3355. int unget;
  3356. const unsigned char *chars;
  3357. size_t nchars_got = 0, nchars_used = 0;
  3358. /*
  3359. * During drag-selects, we do not process terminal input, because
  3360. * the user will want the screen to hold still to be selected.
  3361. */
  3362. if (term->selstate == DRAGGING)
  3363. return;
  3364. unget = -1;
  3365. chars = NULL; /* placate compiler warnings */
  3366. while (nchars_got < nchars_used ||
  3367. unget != -1 ||
  3368. bufchain_size(&term->inbuf) > 0) {
  3369. if (unget != -1) {
  3370. /*
  3371. * Handle a character we left in 'unget' the last time
  3372. * round this loop. This happens if a UTF-8 sequence is
  3373. * aborted early, by containing fewer continuation bytes
  3374. * than its introducer expected: the non-continuation byte
  3375. * that interrupted the sequence must now be processed
  3376. * as a fresh piece of input in its own right.
  3377. */
  3378. c = unget;
  3379. unget = -1;
  3380. } else {
  3381. /*
  3382. * If we're waiting for a terminal resize triggered by an
  3383. * escape sequence, we defer processing the terminal
  3384. * output until we receive acknowledgment from the front
  3385. * end that the resize has happened, so that further
  3386. * output will be processed in the context of the new
  3387. * size.
  3388. *
  3389. * This test goes inside the main while-loop, so that we
  3390. * exit early if we encounter a resize escape sequence
  3391. * part way through term->inbuf.
  3392. *
  3393. * It's also in the branch of this if statement that
  3394. * doesn't deal with a character left in 'unget' by the
  3395. * previous loop iteration, because if we break out of
  3396. * this loop with an ungot character still pending, we'll
  3397. * lose it. (And in any case, if the previous thing that
  3398. * happened was a truncated UTF-8 sequence, then it won't
  3399. * have scheduled a pending resize.)
  3400. */
  3401. if (term->win_resize_pending != WIN_RESIZE_NO)
  3402. break;
  3403. if (nchars_got == nchars_used) {
  3404. /* Delete the previous chunk from the bufchain */
  3405. bufchain_consume(&term->inbuf, nchars_used);
  3406. nchars_used = 0;
  3407. if (bufchain_size(&term->inbuf) == 0)
  3408. break; /* no more data */
  3409. ptrlen data = bufchain_prefix(&term->inbuf);
  3410. chars = data.ptr;
  3411. nchars_got = data.len;
  3412. assert(chars != NULL);
  3413. assert(nchars_used < nchars_got);
  3414. }
  3415. c = chars[nchars_used++];
  3416. /*
  3417. * Optionally log the session traffic to a file. Useful for
  3418. * debugging and possibly also useful for actual logging.
  3419. */
  3420. if (term->logtype == LGTYP_DEBUG && term->logctx)
  3421. logtraffic(term->logctx, (unsigned char) c, LGTYP_DEBUG);
  3422. }
  3423. /* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even
  3424. * be able to display 8-bit characters, but I'll let that go 'cause
  3425. * of i18n.
  3426. */
  3427. /*
  3428. * If we're printing, add the character to the printer
  3429. * buffer.
  3430. */
  3431. if (term->printing) {
  3432. bufchain_add(&term->printer_buf, &c, 1);
  3433. /*
  3434. * If we're in print-only mode, we use a much simpler
  3435. * state machine designed only to recognise the ESC[4i
  3436. * termination sequence.
  3437. */
  3438. if (term->only_printing) {
  3439. if (c == '\033')
  3440. term->print_state = 1;
  3441. else if (c == (unsigned char)'\233')
  3442. term->print_state = 2;
  3443. else if (c == '[' && term->print_state == 1)
  3444. term->print_state = 2;
  3445. else if (c == '4' && term->print_state == 2)
  3446. term->print_state = 3;
  3447. else if (c == 'i' && term->print_state == 3)
  3448. term->print_state = 4;
  3449. else
  3450. term->print_state = 0;
  3451. if (term->print_state == 4) {
  3452. term_print_finish(term);
  3453. }
  3454. continue;
  3455. }
  3456. }
  3457. /* Do character-set translation. */
  3458. if (term->termstate == TOPLEVEL) {
  3459. unsigned long t = term_translate(term, &term->utf8, c);
  3460. switch (t) {
  3461. case UCSINCOMPLETE:
  3462. continue; /* didn't complete a multibyte char */
  3463. case UCSTRUNCATED:
  3464. unget = c;
  3465. /* fall through */
  3466. case UCSINVALID:
  3467. c = UCSERR;
  3468. break;
  3469. default:
  3470. c = t;
  3471. break;
  3472. }
  3473. }
  3474. /*
  3475. * How about C1 controls?
  3476. * Explicitly ignore SCI (0x9a), which we don't translate to DECID.
  3477. */
  3478. if ((c & -32) == 0x80 && term->termstate < DO_CTRLS &&
  3479. !term->vt52_mode && has_compat(VT220)) {
  3480. if (c == 0x9a)
  3481. c = 0;
  3482. else {
  3483. term->termstate = SEEN_ESC;
  3484. term->esc_query = 0;
  3485. c = '@' + (c & 0x1F);
  3486. }
  3487. }
  3488. /* Or the GL control. */
  3489. if (c == '\177' && term->termstate < DO_CTRLS && has_compat(OTHER)) {
  3490. if (term->curs.x && !term->wrapnext)
  3491. term->curs.x--;
  3492. term->wrapnext = false;
  3493. /* destructive backspace might be disabled */
  3494. if (!term->no_dbackspace) {
  3495. check_boundary(term, term->curs.x, term->curs.y);
  3496. check_boundary(term, term->curs.x+1, term->curs.y);
  3497. copy_termchar(scrlineptr(term->curs.y),
  3498. term->curs.x, &term->erase_char);
  3499. }
  3500. seen_disp_event(term);
  3501. } else
  3502. /* Or normal C0 controls. */
  3503. if ((c & ~0x1F) == 0 && term->termstate < DO_CTRLS) {
  3504. switch (c) {
  3505. case '\005': /* ENQ: terminal type query */
  3506. /*
  3507. * Strictly speaking this is VT100 but a VT100 defaults to
  3508. * no response. Other terminals respond at their option.
  3509. *
  3510. * Don't put a CR in the default string as this tends to
  3511. * upset some weird software.
  3512. */
  3513. compatibility(ANSIMIN);
  3514. if (term->ldisc) {
  3515. strbuf *buf = term_input_data_from_charset(
  3516. term, DEFAULT_CODEPAGE,
  3517. term->answerback->s, term->answerback->len);
  3518. ldisc_send(term->ldisc, buf->s, buf->len, false);
  3519. strbuf_free(buf);
  3520. }
  3521. break;
  3522. case '\007': { /* BEL: Bell */
  3523. if (term->termstate == SEEN_OSC ||
  3524. term->termstate == SEEN_OSC_W) {
  3525. /*
  3526. * In an OSC context, BEL is one of the ways to terminate
  3527. * the whole sequence. We process it as such even if we
  3528. * haven't got into the final OSC_STRING state yet, so that
  3529. * OSC sequences without a string will be handled cleanly.
  3530. */
  3531. do_osc(term);
  3532. term->termstate = TOPLEVEL;
  3533. break;
  3534. }
  3535. struct beeptime *newbeep;
  3536. unsigned long ticks;
  3537. ticks = GETTICKCOUNT();
  3538. if (!term->beep_overloaded) {
  3539. newbeep = snew(struct beeptime);
  3540. newbeep->ticks = ticks;
  3541. newbeep->next = NULL;
  3542. if (!term->beephead)
  3543. term->beephead = newbeep;
  3544. else
  3545. term->beeptail->next = newbeep;
  3546. term->beeptail = newbeep;
  3547. term->nbeeps++;
  3548. }
  3549. /*
  3550. * Throw out any beeps that happened more than
  3551. * t seconds ago.
  3552. */
  3553. while (term->beephead &&
  3554. term->beephead->ticks < ticks - term->bellovl_t) {
  3555. struct beeptime *tmp = term->beephead;
  3556. term->beephead = tmp->next;
  3557. sfree(tmp);
  3558. if (!term->beephead)
  3559. term->beeptail = NULL;
  3560. term->nbeeps--;
  3561. }
  3562. if (term->bellovl && term->beep_overloaded &&
  3563. ticks - term->lastbeep >= (unsigned)term->bellovl_s) {
  3564. /*
  3565. * If we're currently overloaded and the
  3566. * last beep was more than s seconds ago,
  3567. * leave overload mode.
  3568. */
  3569. term->beep_overloaded = false;
  3570. } else if (term->bellovl && !term->beep_overloaded &&
  3571. term->nbeeps >= term->bellovl_n) {
  3572. /*
  3573. * Now, if we have n or more beeps
  3574. * remaining in the queue, go into overload
  3575. * mode.
  3576. */
  3577. term->beep_overloaded = true;
  3578. }
  3579. term->lastbeep = ticks;
  3580. /*
  3581. * Perform an actual beep if we're not overloaded.
  3582. */
  3583. if (!term->bellovl || !term->beep_overloaded) {
  3584. win_bell(term->win, term->beep);
  3585. if (term->beep == BELL_VISUAL) {
  3586. term_schedule_vbell(term, false, 0);
  3587. }
  3588. }
  3589. seen_disp_event(term);
  3590. break;
  3591. }
  3592. case '\b': /* BS: Back space */
  3593. if (term->wrapnext) {
  3594. term->wrapnext = false;
  3595. } else if (term->curs.x == 0 &&
  3596. (term->curs.y == 0 || !term->wrap)) {
  3597. /* do nothing */
  3598. } else if (term->curs.x == 0 && term->curs.y > 0) {
  3599. term->curs.x = term->cols - 1, term->curs.y--;
  3600. /*
  3601. * If the line we've just wrapped back on to had the
  3602. * LATTR_WRAPPED2 flag set, it means that the line wrapped
  3603. * because a double-width character was printed with the
  3604. * cursor in the rightmost column, and the best handling
  3605. * available was to leave that column empty and move the
  3606. * whole character to the next line. In that situation,
  3607. * backspacing needs to put the cursor on the previous
  3608. * _logical_ character, i.e. skip the empty space left by
  3609. * the wrapping. This arranges that if an application
  3610. * unaware of the terminal width or cursor position prints
  3611. * a number of printing characters and then tries to return
  3612. * to a particular one of them by emitting the right number
  3613. * of backspaces, it's still the right number even if a
  3614. * line break appeared in a maximally awkward position.
  3615. */
  3616. termline *ldata = scrlineptr(term->curs.y);
  3617. if (term->curs.x > 0 && (ldata->lattr & LATTR_WRAPPED2))
  3618. term->curs.x--;
  3619. } else {
  3620. term->curs.x--;
  3621. }
  3622. seen_disp_event(term);
  3623. break;
  3624. case '\016': /* LS1: Locking-shift one */
  3625. compatibility(VT100);
  3626. term->cset = 1;
  3627. break;
  3628. case '\017': /* LS0: Locking-shift zero */
  3629. compatibility(VT100);
  3630. term->cset = 0;
  3631. break;
  3632. case '\033': /* ESC: Escape */
  3633. if (term->vt52_mode)
  3634. term->termstate = VT52_ESC;
  3635. else if (term->termstate == SEEN_OSC ||
  3636. term->termstate == SEEN_OSC_W) {
  3637. /* Be prepared to terminate an OSC early */
  3638. term->termstate = OSC_MAYBE_ST;
  3639. } else {
  3640. compatibility(ANSIMIN);
  3641. term->termstate = SEEN_ESC;
  3642. term->esc_query = 0;
  3643. }
  3644. break;
  3645. case '\015': /* CR: Carriage return */
  3646. term->curs.x = 0;
  3647. term->wrapnext = false;
  3648. seen_disp_event(term);
  3649. if (term->crhaslf) {
  3650. if (term->curs.y == term->marg_b)
  3651. scroll(term, term->marg_t, term->marg_b, 1, true);
  3652. else if (term->curs.y < term->rows - 1)
  3653. term->curs.y++;
  3654. }
  3655. if (term->logctx)
  3656. logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);
  3657. break;
  3658. case '\014': /* FF: Form feed */
  3659. if (has_compat(SCOANSI)) {
  3660. move(term, 0, 0, 0);
  3661. erase_lots(term, false, false, true);
  3662. if (term->scroll_on_disp)
  3663. term->disptop = 0;
  3664. term->wrapnext = false;
  3665. seen_disp_event(term);
  3666. break;
  3667. }
  3668. case '\013': /* VT: Line tabulation */
  3669. compatibility(VT100);
  3670. case '\012': /* LF: Line feed */
  3671. if (term->curs.y == term->marg_b)
  3672. scroll(term, term->marg_t, term->marg_b, 1, true);
  3673. else if (term->curs.y < term->rows - 1)
  3674. term->curs.y++;
  3675. if (term->lfhascr)
  3676. term->curs.x = 0;
  3677. term->wrapnext = false;
  3678. seen_disp_event(term);
  3679. if (term->logctx)
  3680. logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);
  3681. break;
  3682. case '\t': { /* HT: Character tabulation */
  3683. pos old_curs = term->curs;
  3684. termline *ldata = scrlineptr(term->curs.y);
  3685. do {
  3686. term->curs.x++;
  3687. } while (term->curs.x < term->cols - 1 &&
  3688. !term->tabs[term->curs.x]);
  3689. if ((ldata->lattr & LATTR_MODE) != LATTR_NORM) {
  3690. if (term->curs.x >= term->cols / 2)
  3691. term->curs.x = term->cols / 2 - 1;
  3692. } else {
  3693. if (term->curs.x >= term->cols)
  3694. term->curs.x = term->cols - 1;
  3695. }
  3696. check_selection(term, old_curs, term->curs);
  3697. seen_disp_event(term);
  3698. break;
  3699. }
  3700. }
  3701. } else
  3702. switch (term->termstate) {
  3703. case TOPLEVEL:
  3704. /* Only graphic characters get this far;
  3705. * ctrls are stripped above */
  3706. term_display_graphic_char(term, c);
  3707. term->last_graphic_char = c;
  3708. break;
  3709. case OSC_MAYBE_ST:
  3710. /*
  3711. * This state is virtually identical to SEEN_ESC, with the
  3712. * exception that we have an OSC sequence in the pipeline,
  3713. * and _if_ we see a backslash, we process it.
  3714. */
  3715. if (c == '\\') {
  3716. do_osc(term);
  3717. term->termstate = TOPLEVEL;
  3718. break;
  3719. }
  3720. /* else fall through */
  3721. case SEEN_ESC:
  3722. if (c >= ' ' && c <= '/') {
  3723. if (term->esc_query)
  3724. term->esc_query = -1;
  3725. else
  3726. term->esc_query = c;
  3727. break;
  3728. }
  3729. term->termstate = TOPLEVEL;
  3730. switch (ANSI(c, term->esc_query)) {
  3731. case '[': /* enter CSI mode */
  3732. term->termstate = SEEN_CSI;
  3733. term->esc_nargs = 1;
  3734. term->esc_args[0] = ARG_DEFAULT;
  3735. term->esc_query = 0;
  3736. break;
  3737. case ']': /* OSC: xterm escape sequences */
  3738. /* Compatibility is nasty here, xterm, linux, decterm yuk! */
  3739. compatibility(OTHER);
  3740. term->termstate = SEEN_OSC;
  3741. term->osc_is_apc = false;
  3742. term->osc_strlen = 0;
  3743. term->esc_args[0] = 0;
  3744. term->esc_nargs = 1;
  3745. break;
  3746. case '_': /* APC: application program command */
  3747. /* APC sequences are just a string, terminated by
  3748. * ST or (I've observed in practice) ^G. That is,
  3749. * they have the same termination convention as
  3750. * OSC. So we handle them by going straight into
  3751. * OSC_STRING state and setting a flag indicating
  3752. * that it's not really an OSC. */
  3753. compatibility(OTHER);
  3754. term->termstate = SEEN_OSC;
  3755. term->osc_is_apc = true;
  3756. term->osc_strlen = 0;
  3757. term->esc_args[0] = 0;
  3758. term->esc_nargs = 1;
  3759. break;
  3760. case '7': /* DECSC: save cursor */
  3761. compatibility(VT100);
  3762. save_cursor(term, true);
  3763. break;
  3764. case '8': /* DECRC: restore cursor */
  3765. compatibility(VT100);
  3766. save_cursor(term, false);
  3767. break;
  3768. case '=': /* DECKPAM: Keypad application mode */
  3769. compatibility(VT100);
  3770. term->app_keypad_keys = true;
  3771. break;
  3772. case '>': /* DECKPNM: Keypad numeric mode */
  3773. compatibility(VT100);
  3774. term->app_keypad_keys = false;
  3775. break;
  3776. case 'D': /* IND: exactly equivalent to LF */
  3777. compatibility(VT100);
  3778. if (term->curs.y == term->marg_b)
  3779. scroll(term, term->marg_t, term->marg_b, 1, true);
  3780. else if (term->curs.y < term->rows - 1)
  3781. term->curs.y++;
  3782. term->wrapnext = false;
  3783. seen_disp_event(term);
  3784. break;
  3785. case 'E': /* NEL: exactly equivalent to CR-LF */
  3786. compatibility(VT100);
  3787. term->curs.x = 0;
  3788. if (term->curs.y == term->marg_b)
  3789. scroll(term, term->marg_t, term->marg_b, 1, true);
  3790. else if (term->curs.y < term->rows - 1)
  3791. term->curs.y++;
  3792. term->wrapnext = false;
  3793. seen_disp_event(term);
  3794. break;
  3795. case 'M': /* RI: reverse index - backwards LF */
  3796. compatibility(VT100);
  3797. if (term->curs.y == term->marg_t)
  3798. scroll(term, term->marg_t, term->marg_b, -1, true);
  3799. else if (term->curs.y > 0)
  3800. term->curs.y--;
  3801. term->wrapnext = false;
  3802. seen_disp_event(term);
  3803. break;
  3804. case 'Z': /* DECID: terminal type query */
  3805. compatibility(VT100);
  3806. if (term->ldisc)
  3807. ldisc_send(term->ldisc, term->id_string,
  3808. strlen(term->id_string), false);
  3809. break;
  3810. case 'c': /* RIS: restore power-on settings */
  3811. compatibility(VT100);
  3812. power_on(term, true);
  3813. if (term->ldisc) /* cause ldisc to notice changes */
  3814. ldisc_echoedit_update(term->ldisc);
  3815. if (term->reset_132) {
  3816. if (!term->no_remote_resize)
  3817. term_request_resize(term, 80, term->rows);
  3818. term->reset_132 = false;
  3819. }
  3820. if (term->scroll_on_disp)
  3821. term->disptop = 0;
  3822. seen_disp_event(term);
  3823. break;
  3824. case 'H': /* HTS: set a tab */
  3825. compatibility(VT100);
  3826. term->tabs[term->curs.x] = true;
  3827. break;
  3828. case ANSI('8', '#'): { /* DECALN: fills screen with Es :-) */
  3829. compatibility(VT100);
  3830. termline *ldata;
  3831. int i, j;
  3832. pos scrtop, scrbot;
  3833. for (i = 0; i < term->rows; i++) {
  3834. ldata = scrlineptr(i);
  3835. check_line_size(term, ldata);
  3836. for (j = 0; j < term->cols; j++) {
  3837. copy_termchar(ldata, j,
  3838. &term->basic_erase_char);
  3839. ldata->chars[j].chr = 'E';
  3840. }
  3841. ldata->lattr = LATTR_NORM;
  3842. }
  3843. if (term->scroll_on_disp)
  3844. term->disptop = 0;
  3845. seen_disp_event(term);
  3846. scrtop.x = scrtop.y = 0;
  3847. scrbot.x = 0;
  3848. scrbot.y = term->rows;
  3849. check_selection(term, scrtop, scrbot);
  3850. break;
  3851. }
  3852. case ANSI('3', '#'):
  3853. case ANSI('4', '#'):
  3854. case ANSI('5', '#'):
  3855. case ANSI('6', '#'): {
  3856. compatibility(VT100);
  3857. int nlattr;
  3858. termline *ldata;
  3859. switch (ANSI(c, term->esc_query)) {
  3860. case ANSI('3', '#'): /* DECDHL: 2*height, top */
  3861. nlattr = LATTR_TOP;
  3862. break;
  3863. case ANSI('4', '#'): /* DECDHL: 2*height, bottom */
  3864. nlattr = LATTR_BOT;
  3865. break;
  3866. case ANSI('5', '#'): /* DECSWL: normal */
  3867. nlattr = LATTR_NORM;
  3868. break;
  3869. default: /* case ANSI('6', '#'): DECDWL: 2*width */
  3870. nlattr = LATTR_WIDE;
  3871. break;
  3872. }
  3873. ldata = scrlineptr(term->curs.y);
  3874. check_line_size(term, ldata);
  3875. check_trust_status(term, ldata);
  3876. ldata->lattr = nlattr;
  3877. seen_disp_event(term);
  3878. break;
  3879. }
  3880. /* GZD4: G0 designate 94-set */
  3881. case ANSI('A', '('):
  3882. compatibility(VT100);
  3883. if (!term->no_remote_charset)
  3884. term->cset_attr[0] = CSET_GBCHR;
  3885. break;
  3886. case ANSI('B', '('):
  3887. compatibility(VT100);
  3888. if (!term->no_remote_charset)
  3889. term->cset_attr[0] = CSET_ASCII;
  3890. break;
  3891. case ANSI('0', '('):
  3892. compatibility(VT100);
  3893. if (!term->no_remote_charset)
  3894. term->cset_attr[0] = CSET_LINEDRW;
  3895. break;
  3896. case ANSI('U', '('):
  3897. compatibility(OTHER);
  3898. if (!term->no_remote_charset)
  3899. term->cset_attr[0] = CSET_SCOACS;
  3900. break;
  3901. /* G1D4: G1-designate 94-set */
  3902. case ANSI('A', ')'):
  3903. compatibility(VT100);
  3904. if (!term->no_remote_charset)
  3905. term->cset_attr[1] = CSET_GBCHR;
  3906. break;
  3907. case ANSI('B', ')'):
  3908. compatibility(VT100);
  3909. if (!term->no_remote_charset)
  3910. term->cset_attr[1] = CSET_ASCII;
  3911. break;
  3912. case ANSI('0', ')'):
  3913. compatibility(VT100);
  3914. if (!term->no_remote_charset)
  3915. term->cset_attr[1] = CSET_LINEDRW;
  3916. break;
  3917. case ANSI('U', ')'):
  3918. compatibility(OTHER);
  3919. if (!term->no_remote_charset)
  3920. term->cset_attr[1] = CSET_SCOACS;
  3921. break;
  3922. /* DOCS: Designate other coding system */
  3923. case ANSI('8', '%'): /* Old Linux code */
  3924. case ANSI('G', '%'):
  3925. compatibility(OTHER);
  3926. if (!term->no_remote_charset)
  3927. term->utf = true;
  3928. break;
  3929. case ANSI('@', '%'):
  3930. compatibility(OTHER);
  3931. if (!term->no_remote_charset)
  3932. term->utf = false;
  3933. break;
  3934. }
  3935. break;
  3936. case SEEN_CSI:
  3937. term->termstate = TOPLEVEL; /* default */
  3938. if (isdigit(c)) {
  3939. if (term->esc_nargs <= ARGS_MAX) {
  3940. if (term->esc_args[term->esc_nargs - 1] == ARG_DEFAULT)
  3941. term->esc_args[term->esc_nargs - 1] = 0;
  3942. if (term->esc_args[term->esc_nargs - 1] <=
  3943. UINT_MAX / 10 &&
  3944. term->esc_args[term->esc_nargs - 1] * 10 <=
  3945. UINT_MAX - c - '0')
  3946. term->esc_args[term->esc_nargs - 1] =
  3947. 10 * term->esc_args[term->esc_nargs - 1] +
  3948. c - '0';
  3949. else
  3950. term->esc_args[term->esc_nargs - 1] = UINT_MAX;
  3951. }
  3952. term->termstate = SEEN_CSI;
  3953. } else if (c == ';') {
  3954. if (term->esc_nargs < ARGS_MAX)
  3955. term->esc_args[term->esc_nargs++] = ARG_DEFAULT;
  3956. term->termstate = SEEN_CSI;
  3957. } else if (c < '@') {
  3958. if (term->esc_query)
  3959. term->esc_query = -1;
  3960. else if (c == '?')
  3961. term->esc_query = 1;
  3962. else
  3963. term->esc_query = c;
  3964. term->termstate = SEEN_CSI;
  3965. } else
  3966. #define CLAMP(arg, lim) ((arg) = ((arg) > (lim)) ? (lim) : (arg))
  3967. switch (ANSI(c, term->esc_query)) {
  3968. case 'A': /* CUU: move up N lines */
  3969. CLAMP(term->esc_args[0], term->rows);
  3970. move(term, term->curs.x,
  3971. term->curs.y - def(term->esc_args[0], 1), 1);
  3972. seen_disp_event(term);
  3973. break;
  3974. case 'e': /* VPR: move down N lines */
  3975. compatibility(ANSI);
  3976. /* FALLTHROUGH */
  3977. case 'B': /* CUD: Cursor down */
  3978. CLAMP(term->esc_args[0], term->rows);
  3979. move(term, term->curs.x,
  3980. term->curs.y + def(term->esc_args[0], 1), 1);
  3981. seen_disp_event(term);
  3982. break;
  3983. case 'b': /* REP: repeat previous grap */
  3984. CLAMP(term->esc_args[0], term->rows * term->cols);
  3985. if (term->last_graphic_char) {
  3986. unsigned i;
  3987. for (i = 0; i < term->esc_args[0]; i++)
  3988. term_display_graphic_char(
  3989. term, term->last_graphic_char);
  3990. }
  3991. break;
  3992. case ANSI('c', '>'): /* DA: report xterm version */
  3993. compatibility(OTHER);
  3994. /* this reports xterm version 136 so that VIM can
  3995. use the drag messages from the mouse reporting */
  3996. if (term->ldisc)
  3997. ldisc_send(term->ldisc, "\033[>0;136;0c", 11,
  3998. false);
  3999. break;
  4000. case 'a': /* HPR: move right N cols */
  4001. compatibility(ANSI);
  4002. /* FALLTHROUGH */
  4003. case 'C': /* CUF: Cursor right */
  4004. CLAMP(term->esc_args[0], term->cols);
  4005. move(term, term->curs.x + def(term->esc_args[0], 1),
  4006. term->curs.y, 1);
  4007. seen_disp_event(term);
  4008. break;
  4009. case 'D': /* CUB: move left N cols */
  4010. CLAMP(term->esc_args[0], term->cols);
  4011. move(term, term->curs.x - def(term->esc_args[0], 1),
  4012. term->curs.y, 1);
  4013. seen_disp_event(term);
  4014. break;
  4015. case 'E': /* CNL: move down N lines and CR */
  4016. compatibility(ANSI);
  4017. CLAMP(term->esc_args[0], term->rows);
  4018. move(term, 0,
  4019. term->curs.y + def(term->esc_args[0], 1), 1);
  4020. seen_disp_event(term);
  4021. break;
  4022. case 'F': /* CPL: move up N lines and CR */
  4023. compatibility(ANSI);
  4024. CLAMP(term->esc_args[0], term->rows);
  4025. move(term, 0,
  4026. term->curs.y - def(term->esc_args[0], 1), 1);
  4027. seen_disp_event(term);
  4028. break;
  4029. case 'G': /* CHA */
  4030. case '`': /* HPA: set horizontal posn */
  4031. compatibility(ANSI);
  4032. CLAMP(term->esc_args[0], term->cols);
  4033. move(term, def(term->esc_args[0], 1) - 1,
  4034. term->curs.y, 0);
  4035. seen_disp_event(term);
  4036. break;
  4037. case 'd': /* VPA: set vertical posn */
  4038. compatibility(ANSI);
  4039. CLAMP(term->esc_args[0], term->rows);
  4040. move(term, term->curs.x,
  4041. ((term->dec_om ? term->marg_t : 0) +
  4042. def(term->esc_args[0], 1) - 1),
  4043. (term->dec_om ? 2 : 0));
  4044. seen_disp_event(term);
  4045. break;
  4046. case 'H': /* CUP */
  4047. case 'f': /* HVP: set horz and vert posns at once */
  4048. if (term->esc_nargs < 2)
  4049. term->esc_args[1] = ARG_DEFAULT;
  4050. CLAMP(term->esc_args[0], term->rows);
  4051. CLAMP(term->esc_args[1], term->cols);
  4052. move(term, def(term->esc_args[1], 1) - 1,
  4053. ((term->dec_om ? term->marg_t : 0) +
  4054. def(term->esc_args[0], 1) - 1),
  4055. (term->dec_om ? 2 : 0));
  4056. seen_disp_event(term);
  4057. break;
  4058. case 'J': { /* ED: erase screen or parts of it */
  4059. unsigned int i = def(term->esc_args[0], 0);
  4060. if (i == 3) {
  4061. /* Erase Saved Lines (xterm)
  4062. * This follows Thomas Dickey's xterm. */
  4063. if (!term->no_remote_clearscroll)
  4064. term_clrsb(term);
  4065. } else {
  4066. i++;
  4067. if (i > 3)
  4068. i = 0;
  4069. erase_lots(term, false, !!(i & 2), !!(i & 1));
  4070. }
  4071. if (term->scroll_on_disp)
  4072. term->disptop = 0;
  4073. seen_disp_event(term);
  4074. break;
  4075. }
  4076. case 'K': { /* EL: erase line or parts of it */
  4077. unsigned int i = def(term->esc_args[0], 0) + 1;
  4078. if (i > 3)
  4079. i = 0;
  4080. erase_lots(term, true, !!(i & 2), !!(i & 1));
  4081. seen_disp_event(term);
  4082. break;
  4083. }
  4084. case 'L': /* IL: insert lines */
  4085. compatibility(VT102);
  4086. CLAMP(term->esc_args[0], term->rows);
  4087. if (term->curs.y <= term->marg_b)
  4088. scroll(term, term->curs.y, term->marg_b,
  4089. -def(term->esc_args[0], 1), false);
  4090. seen_disp_event(term);
  4091. break;
  4092. case 'M': /* DL: delete lines */
  4093. compatibility(VT102);
  4094. CLAMP(term->esc_args[0], term->rows);
  4095. if (term->curs.y <= term->marg_b)
  4096. scroll(term, term->curs.y, term->marg_b,
  4097. def(term->esc_args[0], 1),
  4098. true);
  4099. seen_disp_event(term);
  4100. break;
  4101. case '@': /* ICH: insert chars */
  4102. /* XXX VTTEST says this is vt220, vt510 manual says vt102 */
  4103. compatibility(VT102);
  4104. CLAMP(term->esc_args[0], term->cols);
  4105. insch(term, def(term->esc_args[0], 1));
  4106. seen_disp_event(term);
  4107. break;
  4108. case 'P': /* DCH: delete chars */
  4109. compatibility(VT102);
  4110. CLAMP(term->esc_args[0], term->cols);
  4111. insch(term, -def(term->esc_args[0], 1));
  4112. seen_disp_event(term);
  4113. break;
  4114. case 'c': /* DA: terminal type query */
  4115. compatibility(VT100);
  4116. /* This is the response for a VT102 */
  4117. if (term->ldisc)
  4118. ldisc_send(term->ldisc, term->id_string,
  4119. strlen(term->id_string), false);
  4120. break;
  4121. case 'n': /* DSR: cursor position query */
  4122. if (term->ldisc) {
  4123. if (term->esc_args[0] == 6) {
  4124. char buf[32];
  4125. sprintf(buf, "\033[%d;%dR", term->curs.y + 1,
  4126. term->curs.x + 1);
  4127. ldisc_send(term->ldisc, buf, strlen(buf),
  4128. false);
  4129. } else if (term->esc_args[0] == 5) {
  4130. ldisc_send(term->ldisc, "\033[0n", 4, false);
  4131. }
  4132. }
  4133. break;
  4134. case 'h': /* SM: toggle modes to high */
  4135. case ANSI_QUE('h'):
  4136. compatibility(VT100);
  4137. for (int i = 0; i < term->esc_nargs; i++)
  4138. toggle_mode(term, term->esc_args[i],
  4139. term->esc_query, true);
  4140. break;
  4141. case 'i': /* MC: Media copy */
  4142. case ANSI_QUE('i'): {
  4143. compatibility(VT100);
  4144. char *printer;
  4145. if (term->esc_nargs != 1) break;
  4146. if (term->esc_args[0] == 5 &&
  4147. (printer = conf_get_str(term->conf,
  4148. CONF_printer))[0]) {
  4149. term->printing = true;
  4150. term->only_printing = !term->esc_query;
  4151. term->print_state = 0;
  4152. term_print_setup(term, printer);
  4153. } else if (term->esc_args[0] == 4 &&
  4154. term->printing) {
  4155. term_print_finish(term);
  4156. }
  4157. break;
  4158. }
  4159. case 'l': /* RM: toggle modes to low */
  4160. case ANSI_QUE('l'):
  4161. compatibility(VT100);
  4162. for (int i = 0; i < term->esc_nargs; i++)
  4163. toggle_mode(term, term->esc_args[i],
  4164. term->esc_query, false);
  4165. break;
  4166. case 'g': /* TBC: clear tabs */
  4167. compatibility(VT100);
  4168. if (term->esc_nargs == 1) {
  4169. if (term->esc_args[0] == 0) {
  4170. term->tabs[term->curs.x] = false;
  4171. } else if (term->esc_args[0] == 3) {
  4172. int i;
  4173. for (i = 0; i < term->cols; i++)
  4174. term->tabs[i] = false;
  4175. }
  4176. }
  4177. break;
  4178. case 'r': /* DECSTBM: set scroll margins */
  4179. compatibility(VT100);
  4180. if (term->esc_nargs <= 2) {
  4181. int top, bot;
  4182. CLAMP(term->esc_args[0], term->rows);
  4183. CLAMP(term->esc_args[1], term->rows);
  4184. top = def(term->esc_args[0], 1) - 1;
  4185. bot = (term->esc_nargs <= 1
  4186. || term->esc_args[1] == 0 ?
  4187. term->rows :
  4188. def(term->esc_args[1], term->rows)) - 1;
  4189. if (bot >= term->rows)
  4190. bot = term->rows - 1;
  4191. /* VTTEST Bug 9 - if region is less than 2 lines
  4192. * don't change region.
  4193. */
  4194. if (bot - top > 0) {
  4195. term->marg_t = top;
  4196. term->marg_b = bot;
  4197. term->curs.x = 0;
  4198. /*
  4199. * I used to think the cursor should be
  4200. * placed at the top of the newly marginned
  4201. * area. Apparently not: VMS TPU falls over
  4202. * if so.
  4203. *
  4204. * Well actually it should for
  4205. * Origin mode - RDB
  4206. */
  4207. term->curs.y = (term->dec_om ?
  4208. term->marg_t : 0);
  4209. seen_disp_event(term);
  4210. }
  4211. }
  4212. break;
  4213. case 'm': /* SGR: set graphics rendition */
  4214. /*
  4215. * A VT100 without the AVO only had one
  4216. * attribute, either underline or reverse
  4217. * video depending on the cursor type, this
  4218. * was selected by CSI 7m.
  4219. *
  4220. * case 2:
  4221. * This is sometimes DIM, eg on the GIGI and
  4222. * Linux
  4223. * case 8:
  4224. * This is sometimes INVIS various ANSI.
  4225. * case 21:
  4226. * This like 22 disables BOLD, DIM and INVIS
  4227. *
  4228. * The ANSI colours appear on any terminal
  4229. * that has colour (obviously) but the
  4230. * interaction between sgr0 and the colours
  4231. * varies but is usually related to the
  4232. * background colour erase item. The
  4233. * interaction between colour attributes and
  4234. * the mono ones is also very implementation
  4235. * dependent.
  4236. *
  4237. * The 39 and 49 attributes are likely to be
  4238. * unimplemented.
  4239. */
  4240. for (int i = 0; i < term->esc_nargs; i++)
  4241. switch (def(term->esc_args[i], 0)) {
  4242. case 0: /* restore defaults */
  4243. term->curr_attr = term->default_attr;
  4244. term->curr_truecolour =
  4245. term->basic_erase_char.truecolour;
  4246. break;
  4247. case 1: /* enable bold */
  4248. compatibility(VT100AVO);
  4249. term->curr_attr |= ATTR_BOLD;
  4250. break;
  4251. case 2: /* enable dim */
  4252. compatibility(OTHER);
  4253. term->curr_attr |= ATTR_DIM;
  4254. break;
  4255. case 21: /* (enable double underline) */
  4256. compatibility(OTHER);
  4257. case 4: /* enable underline */
  4258. compatibility(VT100AVO);
  4259. term->curr_attr |= ATTR_UNDER;
  4260. break;
  4261. case 5: /* enable blink */
  4262. compatibility(VT100AVO);
  4263. term->curr_attr |= ATTR_BLINK;
  4264. break;
  4265. case 6: /* SCO light bkgrd */
  4266. compatibility(SCOANSI);
  4267. term->blink_is_real = false;
  4268. term->curr_attr |= ATTR_BLINK;
  4269. term_schedule_tblink(term);
  4270. break;
  4271. case 7: /* enable reverse video */
  4272. term->curr_attr |= ATTR_REVERSE;
  4273. break;
  4274. case 9: /* enable strikethrough */
  4275. term->curr_attr |= ATTR_STRIKE;
  4276. break;
  4277. case 10: /* SCO acs off */
  4278. compatibility(SCOANSI);
  4279. if (term->no_remote_charset) break;
  4280. term->sco_acs = 0; break;
  4281. case 11: /* SCO acs on */
  4282. compatibility(SCOANSI);
  4283. if (term->no_remote_charset) break;
  4284. term->sco_acs = 1; break;
  4285. case 12: /* SCO acs on, |0x80 */
  4286. compatibility(SCOANSI);
  4287. if (term->no_remote_charset) break;
  4288. term->sco_acs = 2; break;
  4289. case 22: /* disable bold and dim */
  4290. compatibility2(OTHER, VT220);
  4291. term->curr_attr &= ~(ATTR_BOLD | ATTR_DIM);
  4292. break;
  4293. case 24: /* disable underline */
  4294. compatibility2(OTHER, VT220);
  4295. term->curr_attr &= ~ATTR_UNDER;
  4296. break;
  4297. case 25: /* disable blink */
  4298. compatibility2(OTHER, VT220);
  4299. term->curr_attr &= ~ATTR_BLINK;
  4300. break;
  4301. case 27: /* disable reverse video */
  4302. compatibility2(OTHER, VT220);
  4303. term->curr_attr &= ~ATTR_REVERSE;
  4304. break;
  4305. case 29: /* disable strikethrough */
  4306. term->curr_attr &= ~ATTR_STRIKE;
  4307. break;
  4308. case 30:
  4309. case 31:
  4310. case 32:
  4311. case 33:
  4312. case 34:
  4313. case 35:
  4314. case 36:
  4315. case 37:
  4316. /* foreground */
  4317. term->curr_truecolour.fg.enabled = false;
  4318. term->curr_attr &= ~ATTR_FGMASK;
  4319. term->curr_attr |=
  4320. (term->esc_args[i] - 30)<<ATTR_FGSHIFT;
  4321. break;
  4322. case 90:
  4323. case 91:
  4324. case 92:
  4325. case 93:
  4326. case 94:
  4327. case 95:
  4328. case 96:
  4329. case 97:
  4330. /* aixterm-style bright foreground */
  4331. term->curr_truecolour.fg.enabled = false;
  4332. term->curr_attr &= ~ATTR_FGMASK;
  4333. term->curr_attr |=
  4334. ((term->esc_args[i] - 90 + 8)
  4335. << ATTR_FGSHIFT);
  4336. break;
  4337. case 39: /* default-foreground */
  4338. term->curr_truecolour.fg.enabled = false;
  4339. term->curr_attr &= ~ATTR_FGMASK;
  4340. term->curr_attr |= ATTR_DEFFG;
  4341. break;
  4342. case 40:
  4343. case 41:
  4344. case 42:
  4345. case 43:
  4346. case 44:
  4347. case 45:
  4348. case 46:
  4349. case 47:
  4350. /* background */
  4351. term->curr_truecolour.bg.enabled = false;
  4352. term->curr_attr &= ~ATTR_BGMASK;
  4353. term->curr_attr |=
  4354. (term->esc_args[i] - 40)<<ATTR_BGSHIFT;
  4355. break;
  4356. case 100:
  4357. case 101:
  4358. case 102:
  4359. case 103:
  4360. case 104:
  4361. case 105:
  4362. case 106:
  4363. case 107:
  4364. /* aixterm-style bright background */
  4365. term->curr_truecolour.bg.enabled = false;
  4366. term->curr_attr &= ~ATTR_BGMASK;
  4367. term->curr_attr |=
  4368. ((term->esc_args[i] - 100 + 8)
  4369. << ATTR_BGSHIFT);
  4370. break;
  4371. case 49: /* default-background */
  4372. term->curr_truecolour.bg.enabled = false;
  4373. term->curr_attr &= ~ATTR_BGMASK;
  4374. term->curr_attr |= ATTR_DEFBG;
  4375. break;
  4376. /*
  4377. * 256-colour and true-colour
  4378. * sequences. A 256-colour
  4379. * foreground is selected by a
  4380. * sequence of 3 arguments in the
  4381. * form 38;5;n, where n is in the
  4382. * range 0-255. A true-colour RGB
  4383. * triple is selected by 5 args of
  4384. * the form 38;2;r;g;b. Replacing
  4385. * the initial 38 with 48 in both
  4386. * cases selects the same colour
  4387. * as the background.
  4388. */
  4389. case 38:
  4390. if (i+2 < term->esc_nargs &&
  4391. term->esc_args[i+1] == 5) {
  4392. term->curr_attr &= ~ATTR_FGMASK;
  4393. term->curr_attr |=
  4394. ((term->esc_args[i+2] & 0xFF)
  4395. << ATTR_FGSHIFT);
  4396. term->curr_truecolour.fg =
  4397. optionalrgb_none;
  4398. i += 2;
  4399. }
  4400. if (i + 4 < term->esc_nargs &&
  4401. term->esc_args[i + 1] == 2) {
  4402. parse_optionalrgb(
  4403. &term->curr_truecolour.fg,
  4404. term->esc_args + (i+2));
  4405. i += 4;
  4406. }
  4407. break;
  4408. case 48:
  4409. if (i+2 < term->esc_nargs &&
  4410. term->esc_args[i+1] == 5) {
  4411. term->curr_attr &= ~ATTR_BGMASK;
  4412. term->curr_attr |=
  4413. ((term->esc_args[i+2] & 0xFF)
  4414. << ATTR_BGSHIFT);
  4415. term->curr_truecolour.bg =
  4416. optionalrgb_none;
  4417. i += 2;
  4418. }
  4419. if (i + 4 < term->esc_nargs &&
  4420. term->esc_args[i+1] == 2) {
  4421. parse_optionalrgb(
  4422. &term->curr_truecolour.bg,
  4423. term->esc_args + (i+2));
  4424. i += 4;
  4425. }
  4426. break;
  4427. }
  4428. set_erase_char(term);
  4429. break;
  4430. case 's': /* save cursor */
  4431. save_cursor(term, true);
  4432. break;
  4433. case 'u': /* restore cursor */
  4434. save_cursor(term, false);
  4435. break;
  4436. case 't': /* DECSLPP: set page size - ie window height */
  4437. /*
  4438. * VT340/VT420 sequence DECSLPP, DEC only allows values
  4439. * 24/25/36/48/72/144 other emulators (eg dtterm) use
  4440. * illegal values (eg first arg 1..9) for window changing
  4441. * and reports.
  4442. */
  4443. if (term->esc_nargs <= 1
  4444. && (term->esc_args[0] < 1 ||
  4445. term->esc_args[0] >= 24)) {
  4446. compatibility(VT340TEXT);
  4447. if (!term->no_remote_resize)
  4448. term_request_resize(term, term->cols, 24);
  4449. deselect(term);
  4450. } else if (term->esc_nargs >= 1 &&
  4451. term->esc_args[0] >= 1 &&
  4452. term->esc_args[0] < 24) {
  4453. compatibility(OTHER);
  4454. switch (term->esc_args[0]) {
  4455. int len;
  4456. char buf[80];
  4457. const char *p;
  4458. case 1:
  4459. term->win_minimise_pending = true;
  4460. term->win_minimise_enable = false;
  4461. term_schedule_update(term);
  4462. break;
  4463. case 2:
  4464. term->win_minimise_pending = true;
  4465. term->win_minimise_enable = true;
  4466. term_schedule_update(term);
  4467. break;
  4468. case 3:
  4469. if (term->esc_nargs >= 3) {
  4470. if (!term->no_remote_resize) {
  4471. term->win_move_pending = true;
  4472. term->win_move_pending_x =
  4473. def(term->esc_args[1], 0);
  4474. term->win_move_pending_y =
  4475. def(term->esc_args[2], 0);
  4476. term_schedule_update(term);
  4477. }
  4478. }
  4479. break;
  4480. case 4:
  4481. /* We should resize the window to a given
  4482. * size in pixels here, but currently our
  4483. * resizing code isn't healthy enough to
  4484. * manage it. */
  4485. break;
  4486. case 5:
  4487. /* move to top */
  4488. term->win_zorder_pending = true;
  4489. term->win_zorder_top = true;
  4490. term_schedule_update(term);
  4491. break;
  4492. case 6:
  4493. /* move to bottom */
  4494. term->win_zorder_pending = true;
  4495. term->win_zorder_top = false;
  4496. term_schedule_update(term);
  4497. break;
  4498. case 7:
  4499. term->win_refresh_pending = true;
  4500. term_schedule_update(term);
  4501. break;
  4502. case 8:
  4503. if (term->esc_nargs >= 3 &&
  4504. !term->no_remote_resize) {
  4505. term_request_resize(
  4506. term,
  4507. def(term->esc_args[2],
  4508. term->conf_width),
  4509. def(term->esc_args[1],
  4510. term->conf_height));
  4511. }
  4512. break;
  4513. case 9:
  4514. if (term->esc_nargs >= 2) {
  4515. term->win_maximise_pending = true;
  4516. term->win_maximise_enable =
  4517. term->esc_args[1];
  4518. term_schedule_update(term);
  4519. }
  4520. break;
  4521. case 11:
  4522. if (term->ldisc)
  4523. ldisc_send(term->ldisc, term->minimised ?
  4524. "\033[2t" : "\033[1t", 4,
  4525. false);
  4526. break;
  4527. case 13:
  4528. if (term->ldisc) {
  4529. len = sprintf(buf, "\033[3;%u;%ut",
  4530. term->winpos_x,
  4531. term->winpos_y);
  4532. ldisc_send(term->ldisc, buf, len, false);
  4533. }
  4534. break;
  4535. case 14:
  4536. if (term->ldisc) {
  4537. len = sprintf(buf, "\033[4;%u;%ut",
  4538. term->winpixsize_y,
  4539. term->winpixsize_x);
  4540. ldisc_send(term->ldisc, buf, len, false);
  4541. }
  4542. break;
  4543. case 18:
  4544. if (term->ldisc) {
  4545. len = sprintf(buf, "\033[8;%d;%dt",
  4546. term->rows, term->cols);
  4547. ldisc_send(term->ldisc, buf, len, false);
  4548. }
  4549. break;
  4550. case 19:
  4551. /*
  4552. * Hmmm. Strictly speaking we
  4553. * should return `the size of the
  4554. * screen in characters', but
  4555. * that's not easy: (a) window
  4556. * furniture being what it is it's
  4557. * hard to compute, and (b) in
  4558. * resize-font mode maximising the
  4559. * window wouldn't change the
  4560. * number of characters. *shrug*. I
  4561. * think we'll ignore it for the
  4562. * moment and see if anyone
  4563. * complains, and then ask them
  4564. * what they would like it to do.
  4565. */
  4566. break;
  4567. case 20:
  4568. if (term->ldisc &&
  4569. term->remote_qtitle_action != TITLE_NONE) {
  4570. if(term->remote_qtitle_action == TITLE_REAL)
  4571. p = term->icon_title;
  4572. else
  4573. p = EMPTY_WINDOW_TITLE;
  4574. len = strlen(p);
  4575. ldisc_send(term->ldisc, "\033]L", 3,
  4576. false);
  4577. ldisc_send(term->ldisc, p, len, false);
  4578. ldisc_send(term->ldisc, "\033\\", 2,
  4579. false);
  4580. }
  4581. break;
  4582. case 21:
  4583. if (term->ldisc &&
  4584. term->remote_qtitle_action != TITLE_NONE) {
  4585. if(term->remote_qtitle_action == TITLE_REAL)
  4586. p = term->window_title;
  4587. else
  4588. p = EMPTY_WINDOW_TITLE;
  4589. len = strlen(p);
  4590. ldisc_send(term->ldisc, "\033]l", 3,
  4591. false);
  4592. ldisc_send(term->ldisc, p, len, false);
  4593. ldisc_send(term->ldisc, "\033\\", 2,
  4594. false);
  4595. }
  4596. break;
  4597. }
  4598. }
  4599. break;
  4600. case 'S': /* SU: Scroll up */
  4601. CLAMP(term->esc_args[0], term->rows);
  4602. compatibility(SCOANSI);
  4603. scroll(term, term->marg_t, term->marg_b,
  4604. def(term->esc_args[0], 1), true);
  4605. term->wrapnext = false;
  4606. break;
  4607. case 'T': /* SD: Scroll down */
  4608. CLAMP(term->esc_args[0], term->rows);
  4609. compatibility(SCOANSI);
  4610. scroll(term, term->marg_t, term->marg_b,
  4611. -def(term->esc_args[0], 1), true);
  4612. term->wrapnext = false;
  4613. break;
  4614. case ANSI('|', '*'): /* DECSNLS */
  4615. /*
  4616. * Set number of lines on screen
  4617. * VT420 uses VGA like hardware and can
  4618. * support any size in reasonable range
  4619. * (24..49 AIUI) with no default specified.
  4620. */
  4621. compatibility(VT420);
  4622. if (term->esc_nargs == 1 && term->esc_args[0] > 0) {
  4623. if (!term->no_remote_resize)
  4624. term_request_resize(
  4625. term,
  4626. term->cols,
  4627. def(term->esc_args[0], term->conf_height));
  4628. deselect(term);
  4629. }
  4630. break;
  4631. case ANSI('|', '$'): /* DECSCPP */
  4632. /*
  4633. * Set number of columns per page
  4634. * Docs imply range is only 80 or 132, but
  4635. * I'll allow any.
  4636. */
  4637. compatibility(VT340TEXT);
  4638. if (term->esc_nargs <= 1) {
  4639. if (!term->no_remote_resize)
  4640. term_request_resize(
  4641. term,
  4642. def(term->esc_args[0], term->conf_width),
  4643. term->rows);
  4644. deselect(term);
  4645. }
  4646. break;
  4647. case 'X': { /* ECH: write N spaces w/o moving cursor */
  4648. /* XXX VTTEST says this is vt220, vt510 manual
  4649. * says vt100 */
  4650. compatibility(ANSIMIN);
  4651. CLAMP(term->esc_args[0], term->cols);
  4652. int n = def(term->esc_args[0], 1);
  4653. pos cursplus;
  4654. int p = term->curs.x;
  4655. termline *cline = scrlineptr(term->curs.y);
  4656. check_trust_status(term, cline);
  4657. if (n > term->cols - term->curs.x)
  4658. n = term->cols - term->curs.x;
  4659. cursplus = term->curs;
  4660. cursplus.x += n;
  4661. check_boundary(term, term->curs.x, term->curs.y);
  4662. check_boundary(term, term->curs.x+n, term->curs.y);
  4663. check_selection(term, term->curs, cursplus);
  4664. while (n--)
  4665. copy_termchar(cline, p++,
  4666. &term->erase_char);
  4667. seen_disp_event(term);
  4668. break;
  4669. }
  4670. case 'x': /* DECREQTPARM: report terminal characteristics */
  4671. compatibility(VT100);
  4672. if (term->ldisc) {
  4673. char buf[32];
  4674. int i = def(term->esc_args[0], 0);
  4675. if (i == 0 || i == 1) {
  4676. strcpy(buf, "\033[2;1;1;112;112;1;0x");
  4677. buf[2] += i;
  4678. ldisc_send(term->ldisc, buf, 20, false);
  4679. }
  4680. }
  4681. break;
  4682. case 'Z': { /* CBT */
  4683. compatibility(OTHER);
  4684. CLAMP(term->esc_args[0], term->cols);
  4685. int i = def(term->esc_args[0], 1);
  4686. pos old_curs = term->curs;
  4687. for (; i>0 && term->curs.x>0; i--) {
  4688. do {
  4689. term->curs.x--;
  4690. } while (term->curs.x >0 &&
  4691. !term->tabs[term->curs.x]);
  4692. }
  4693. check_selection(term, old_curs, term->curs);
  4694. break;
  4695. }
  4696. case ANSI('c', '='): /* Hide or Show Cursor */
  4697. compatibility(SCOANSI);
  4698. switch(term->esc_args[0]) {
  4699. case 0: /* hide cursor */
  4700. term->cursor_on = false;
  4701. break;
  4702. case 1: /* restore cursor */
  4703. term->big_cursor = false;
  4704. term->cursor_on = true;
  4705. break;
  4706. case 2: /* block cursor */
  4707. term->big_cursor = true;
  4708. term->cursor_on = true;
  4709. break;
  4710. }
  4711. break;
  4712. case ANSI('C', '='):
  4713. /*
  4714. * set cursor start on scanline esc_args[0] and
  4715. * end on scanline esc_args[1].If you set
  4716. * the bottom scan line to a value less than
  4717. * the top scan line, the cursor will disappear.
  4718. */
  4719. compatibility(SCOANSI);
  4720. if (term->esc_nargs >= 2) {
  4721. if (term->esc_args[0] > term->esc_args[1])
  4722. term->cursor_on = false;
  4723. else
  4724. term->cursor_on = true;
  4725. }
  4726. break;
  4727. case ANSI('D', '='):
  4728. compatibility(SCOANSI);
  4729. term->blink_is_real = false;
  4730. term_schedule_tblink(term);
  4731. if (term->esc_args[0]>=1)
  4732. term->curr_attr |= ATTR_BLINK;
  4733. else
  4734. term->curr_attr &= ~ATTR_BLINK;
  4735. break;
  4736. case ANSI('E', '='):
  4737. compatibility(SCOANSI);
  4738. term->blink_is_real = (term->esc_args[0] >= 1);
  4739. term_schedule_tblink(term);
  4740. break;
  4741. case ANSI('F', '='): /* set normal foreground */
  4742. compatibility(SCOANSI);
  4743. if (term->esc_args[0] < 16) {
  4744. long colour =
  4745. (sco2ansicolour[term->esc_args[0] & 0x7] |
  4746. (term->esc_args[0] & 0x8)) <<
  4747. ATTR_FGSHIFT;
  4748. term->curr_attr &= ~ATTR_FGMASK;
  4749. term->curr_attr |= colour;
  4750. term->curr_truecolour.fg = optionalrgb_none;
  4751. term->default_attr &= ~ATTR_FGMASK;
  4752. term->default_attr |= colour;
  4753. set_erase_char(term);
  4754. }
  4755. break;
  4756. case ANSI('G', '='): /* set normal background */
  4757. compatibility(SCOANSI);
  4758. if (term->esc_args[0] < 16) {
  4759. long colour =
  4760. (sco2ansicolour[term->esc_args[0] & 0x7] |
  4761. (term->esc_args[0] & 0x8)) <<
  4762. ATTR_BGSHIFT;
  4763. term->curr_attr &= ~ATTR_BGMASK;
  4764. term->curr_attr |= colour;
  4765. term->curr_truecolour.bg = optionalrgb_none;
  4766. term->default_attr &= ~ATTR_BGMASK;
  4767. term->default_attr |= colour;
  4768. set_erase_char(term);
  4769. }
  4770. break;
  4771. case ANSI('L', '='):
  4772. compatibility(SCOANSI);
  4773. term->use_bce = (term->esc_args[0] <= 0);
  4774. set_erase_char(term);
  4775. break;
  4776. case ANSI('p', '"'): /* DECSCL: set compat level */
  4777. /*
  4778. * Allow the host to make this emulator a
  4779. * 'perfect' VT102. This first appeared in
  4780. * the VT220, but we do need to get back to
  4781. * PuTTY mode so I won't check it.
  4782. *
  4783. * The arg in 40..42,50 are a PuTTY extension.
  4784. * The 2nd arg, 8bit vs 7bit is not checked.
  4785. *
  4786. * Setting VT102 mode should also change
  4787. * the Fkeys to generate PF* codes as a
  4788. * real VT102 has no Fkeys. The VT220 does
  4789. * this, F11..F13 become ESC,BS,LF other
  4790. * Fkeys send nothing.
  4791. *
  4792. * Note ESC c will NOT change this!
  4793. */
  4794. switch (term->esc_args[0]) {
  4795. case 61:
  4796. term->compatibility_level &= ~TM_VTXXX;
  4797. term->compatibility_level |= TM_VT102;
  4798. break;
  4799. case 62:
  4800. term->compatibility_level &= ~TM_VTXXX;
  4801. term->compatibility_level |= TM_VT220;
  4802. break;
  4803. default:
  4804. if (term->esc_args[0] > 60 &&
  4805. term->esc_args[0] < 70)
  4806. term->compatibility_level |= TM_VTXXX;
  4807. break;
  4808. case 40:
  4809. term->compatibility_level &= TM_VTXXX;
  4810. break;
  4811. case 41:
  4812. term->compatibility_level = TM_PUTTY;
  4813. break;
  4814. case 42:
  4815. term->compatibility_level = TM_SCOANSI;
  4816. break;
  4817. case ARG_DEFAULT:
  4818. term->compatibility_level = TM_PUTTY;
  4819. break;
  4820. case 50:
  4821. break;
  4822. }
  4823. /* Change the response to CSI c */
  4824. if (term->esc_args[0] == 50) {
  4825. int i;
  4826. char lbuf[64];
  4827. strcpy(term->id_string, "\033[?");
  4828. for (i = 1; i < term->esc_nargs; i++) {
  4829. if (i != 1)
  4830. strcat(term->id_string, ";");
  4831. sprintf(lbuf, "%u", term->esc_args[i]);
  4832. strcat(term->id_string, lbuf);
  4833. }
  4834. strcat(term->id_string, "c");
  4835. }
  4836. #if 0
  4837. /* Is this a good idea ?
  4838. * Well we should do a soft reset at this point ...
  4839. */
  4840. if (!has_compat(VT420) && has_compat(VT100)) {
  4841. if (!term->no_remote_resize)
  4842. term_request_resize(term,
  4843. term->reset_132 ? 132 : 80,
  4844. 24);
  4845. }
  4846. #endif
  4847. break;
  4848. }
  4849. break;
  4850. case SEEN_OSC:
  4851. term->osc_w = false;
  4852. switch (c) {
  4853. case 'P': /* Linux palette sequence */
  4854. term->termstate = SEEN_OSC_P;
  4855. term->osc_strlen = 0;
  4856. break;
  4857. case 'R': /* Linux palette reset */
  4858. palette_reset(term, false);
  4859. term_invalidate(term);
  4860. term->termstate = TOPLEVEL;
  4861. break;
  4862. case 'W': /* word-set */
  4863. term->termstate = SEEN_OSC_W;
  4864. term->osc_w = true;
  4865. break;
  4866. case '0':
  4867. case '1':
  4868. case '2':
  4869. case '3':
  4870. case '4':
  4871. case '5':
  4872. case '6':
  4873. case '7':
  4874. case '8':
  4875. case '9':
  4876. if (term->esc_args[term->esc_nargs-1] <= UINT_MAX / 10 &&
  4877. term->esc_args[term->esc_nargs-1] * 10 <= UINT_MAX - c - '0')
  4878. term->esc_args[term->esc_nargs-1] =
  4879. 10 * term->esc_args[term->esc_nargs-1] + c - '0';
  4880. else
  4881. term->esc_args[term->esc_nargs-1] = UINT_MAX;
  4882. break;
  4883. case 0x9C:
  4884. /* Terminate even though we aren't in OSC_STRING yet */
  4885. do_osc(term);
  4886. term->termstate = TOPLEVEL;
  4887. break;
  4888. case 0xC2:
  4889. if (in_utf(term)) {
  4890. /* Or be prepared for the UTF-8 version of that */
  4891. term->termstate = OSC_MAYBE_ST_UTF8;
  4892. }
  4893. break;
  4894. default:
  4895. /*
  4896. * _Most_ other characters here terminate the
  4897. * immediate parsing of the OSC sequence and go
  4898. * into OSC_STRING state, but we deal with a
  4899. * couple of exceptions first.
  4900. */
  4901. if (c == 'L' && term->esc_args[0] == 2) {
  4902. /*
  4903. * Grotty hack to support xterm and DECterm title
  4904. * sequences concurrently.
  4905. */
  4906. term->esc_args[0] = 1;
  4907. } else if (c == ';' && term->esc_nargs == 1 &&
  4908. term->esc_args[0] == 4) {
  4909. /*
  4910. * xterm's OSC 4 sequence to query the current
  4911. * RGB value of a colour takes a second
  4912. * numeric argument which is easiest to parse
  4913. * using the existing system rather than in
  4914. * do_osc.
  4915. */
  4916. term->esc_args[term->esc_nargs++] = 0;
  4917. } else {
  4918. term->termstate = OSC_STRING;
  4919. term->osc_strlen = 0;
  4920. }
  4921. }
  4922. break;
  4923. case OSC_STRING:
  4924. /*
  4925. * OSC sequences can be terminated or aborted in
  4926. * various ways.
  4927. *
  4928. * The official way to terminate an OSC, per written
  4929. * standards, is the String Terminator, SC. That can
  4930. * appear in a 7-bit two-character form ESC \, or as
  4931. * an 8-bit C1 control 0x9C.
  4932. *
  4933. * We only accept 0x9C in circumstances where it
  4934. * doesn't interfere with our main character set
  4935. * processing: so in ISO 8859-1, for example, the byte
  4936. * 0x9C is interpreted as ST, but in CP437 it's
  4937. * interpreted as an ordinary printing character (as
  4938. * it happens, the pound sign), because you might
  4939. * perfectly well want to put it in the window title
  4940. * like any other printing character.
  4941. *
  4942. * In particular, in UTF-8 mode, 0x9C is a perfectly
  4943. * valid continuation byte for an ordinary printing
  4944. * character, so we don't accept the C1 control form
  4945. * of ST unless it appears as a full UTF-8 character
  4946. * in its own right, i.e. bytes 0xC2 0x9C.
  4947. *
  4948. * BEL is also treated as a clean termination of OSC,
  4949. * which I believe was a behaviour introduced by
  4950. * xterm.
  4951. *
  4952. * To prevent run-on storage of OSC data forever if
  4953. * emission of a control sequence is interrupted, we
  4954. * also treat various control characters as illegal,
  4955. * so that they abort the OSC without processing it
  4956. * and return to TOPLEVEL state. These are CR, LF, and
  4957. * any ESC that is *not* followed by \.
  4958. */
  4959. if (c == '\012' || c == '\015') {
  4960. /* CR or LF aborts */
  4961. term->termstate = TOPLEVEL;
  4962. break;
  4963. }
  4964. if (c == '\033') {
  4965. /* ESC goes into a state where we wait to see if
  4966. * the next character is \ */
  4967. term->termstate = OSC_MAYBE_ST;
  4968. break;
  4969. }
  4970. if (c == '\007' || (c == 0x9C && !in_utf(term) &&
  4971. term->ucsdata->unitab_ctrl[c] != 0xFF)) {
  4972. /* BEL, or the C1 ST appearing as a one-byte
  4973. * encoding, cleanly terminates the OSC right here */
  4974. do_osc(term);
  4975. term->termstate = TOPLEVEL;
  4976. break;
  4977. }
  4978. if (c == 0xC2 && in_utf(term)) {
  4979. /* 0xC2 is the UTF-8 character that might
  4980. * introduce the encoding of C1 ST */
  4981. term->termstate = OSC_MAYBE_ST_UTF8;
  4982. break;
  4983. }
  4984. /* Anything else gets added to the string */
  4985. if (term->osc_strlen < OSC_STR_MAX)
  4986. term->osc_string[term->osc_strlen++] = (char)c;
  4987. break;
  4988. case OSC_MAYBE_ST_UTF8:
  4989. /* In UTF-8 mode, we've seen C2, so are we now seeing
  4990. * 9C? */
  4991. if (c == 0x9C) {
  4992. /* Yes, so cleanly terminate the OSC */
  4993. do_osc(term);
  4994. term->termstate = TOPLEVEL;
  4995. break;
  4996. }
  4997. /* No, so append the pending C2 byte to the OSC string
  4998. * followed by the current character, and go back to
  4999. * OSC string accumulation */
  5000. if (term->osc_strlen < OSC_STR_MAX)
  5001. term->osc_string[term->osc_strlen++] = 0xC2;
  5002. if (term->osc_strlen < OSC_STR_MAX)
  5003. term->osc_string[term->osc_strlen++] = (char)c;
  5004. term->termstate = OSC_STRING;
  5005. break;
  5006. case SEEN_OSC_P: {
  5007. int max = (term->osc_strlen == 0 ? 21 : 15);
  5008. int val;
  5009. if ((int)c >= '0' && (int)c <= '9')
  5010. val = c - '0';
  5011. else if ((int)c >= 'A' && (int)c <= 'A' + max - 10)
  5012. val = c - 'A' + 10;
  5013. else if ((int)c >= 'a' && (int)c <= 'a' + max - 10)
  5014. val = c - 'a' + 10;
  5015. else {
  5016. term->termstate = TOPLEVEL;
  5017. break;
  5018. }
  5019. term->osc_string[term->osc_strlen++] = val;
  5020. if (term->osc_strlen >= 7) {
  5021. unsigned oscp_index = term->osc_string[0];
  5022. assert(oscp_index < OSCP_NCOLOURS);
  5023. unsigned osc4_index =
  5024. colour_indices_oscp_to_osc4[oscp_index];
  5025. rgb *value = &term->subpalettes[SUBPAL_SESSION].values[
  5026. osc4_index];
  5027. value->r = term->osc_string[1] * 16 + term->osc_string[2];
  5028. value->g = term->osc_string[3] * 16 + term->osc_string[4];
  5029. value->b = term->osc_string[5] * 16 + term->osc_string[6];
  5030. term->subpalettes[SUBPAL_SESSION].present[
  5031. osc4_index] = true;
  5032. palette_rebuild(term);
  5033. term->termstate = TOPLEVEL;
  5034. }
  5035. break;
  5036. }
  5037. case SEEN_OSC_W:
  5038. switch (c) {
  5039. case '0':
  5040. case '1':
  5041. case '2':
  5042. case '3':
  5043. case '4':
  5044. case '5':
  5045. case '6':
  5046. case '7':
  5047. case '8':
  5048. case '9':
  5049. if (term->esc_args[0] <= UINT_MAX / 10 &&
  5050. term->esc_args[0] * 10 <= UINT_MAX - c - '0')
  5051. term->esc_args[0] = 10 * term->esc_args[0] + c - '0';
  5052. else
  5053. term->esc_args[0] = UINT_MAX;
  5054. break;
  5055. case 0x9C:
  5056. /* Terminate even though we aren't in OSC_STRING yet */
  5057. do_osc(term);
  5058. term->termstate = TOPLEVEL;
  5059. break;
  5060. case 0xC2:
  5061. if (in_utf(term)) {
  5062. /* Or be prepared for the UTF-8 version of that */
  5063. term->termstate = OSC_MAYBE_ST_UTF8;
  5064. }
  5065. break;
  5066. default:
  5067. term->termstate = OSC_STRING;
  5068. term->osc_strlen = 0;
  5069. }
  5070. break;
  5071. case VT52_ESC:
  5072. term->termstate = TOPLEVEL;
  5073. switch (c) {
  5074. case 'A':
  5075. move(term, term->curs.x, term->curs.y - 1, 1);
  5076. break;
  5077. case 'B':
  5078. move(term, term->curs.x, term->curs.y + 1, 1);
  5079. break;
  5080. case 'C':
  5081. move(term, term->curs.x + 1, term->curs.y, 1);
  5082. break;
  5083. case 'D':
  5084. move(term, term->curs.x - 1, term->curs.y, 1);
  5085. break;
  5086. /*
  5087. * From the VT100 Manual
  5088. * NOTE: The special graphics characters in the VT100
  5089. * are different from those in the VT52
  5090. *
  5091. * From VT102 manual:
  5092. * 137 _ Blank - Same
  5093. * 140 ` Reserved - Humm.
  5094. * 141 a Solid rectangle - Similar
  5095. * 142 b 1/ - Top half of fraction for the
  5096. * 143 c 3/ - subscript numbers below.
  5097. * 144 d 5/
  5098. * 145 e 7/
  5099. * 146 f Degrees - Same
  5100. * 147 g Plus or minus - Same
  5101. * 150 h Right arrow
  5102. * 151 i Ellipsis (dots)
  5103. * 152 j Divide by
  5104. * 153 k Down arrow
  5105. * 154 l Bar at scan 0
  5106. * 155 m Bar at scan 1
  5107. * 156 n Bar at scan 2
  5108. * 157 o Bar at scan 3 - Similar
  5109. * 160 p Bar at scan 4 - Similar
  5110. * 161 q Bar at scan 5 - Similar
  5111. * 162 r Bar at scan 6 - Same
  5112. * 163 s Bar at scan 7 - Similar
  5113. * 164 t Subscript 0
  5114. * 165 u Subscript 1
  5115. * 166 v Subscript 2
  5116. * 167 w Subscript 3
  5117. * 170 x Subscript 4
  5118. * 171 y Subscript 5
  5119. * 172 z Subscript 6
  5120. * 173 { Subscript 7
  5121. * 174 | Subscript 8
  5122. * 175 } Subscript 9
  5123. * 176 ~ Paragraph
  5124. *
  5125. */
  5126. case 'F':
  5127. term->cset_attr[term->cset = 0] = CSET_LINEDRW;
  5128. break;
  5129. case 'G':
  5130. term->cset_attr[term->cset = 0] = CSET_ASCII;
  5131. break;
  5132. case 'H':
  5133. move(term, 0, 0, 0);
  5134. break;
  5135. case 'I':
  5136. if (term->curs.y == 0) {
  5137. scroll(term, 0, term->rows - 1, -1, true);
  5138. } else if (term->curs.y > 0) {
  5139. term->curs.y--;
  5140. seen_disp_event(term);
  5141. }
  5142. term->wrapnext = false;
  5143. break;
  5144. case 'J':
  5145. erase_lots(term, false, false, true);
  5146. if (term->scroll_on_disp)
  5147. term->disptop = 0;
  5148. break;
  5149. case 'K':
  5150. erase_lots(term, true, false, true);
  5151. break;
  5152. #if 0
  5153. case 'V':
  5154. /* XXX Print cursor line */
  5155. break;
  5156. case 'W':
  5157. /* XXX Start controller mode */
  5158. break;
  5159. case 'X':
  5160. /* XXX Stop controller mode */
  5161. break;
  5162. #endif
  5163. case 'Y':
  5164. term->termstate = VT52_Y1;
  5165. break;
  5166. case 'Z':
  5167. if (term->ldisc)
  5168. ldisc_send(term->ldisc, "\033/Z", 3, false);
  5169. break;
  5170. case '=':
  5171. term->app_keypad_keys = true;
  5172. break;
  5173. case '>':
  5174. term->app_keypad_keys = false;
  5175. break;
  5176. case '<':
  5177. /* XXX This should switch to VT100 mode not current or default
  5178. * VT mode. But this will only have effect in a VT220+
  5179. * emulation.
  5180. */
  5181. term->vt52_mode = false;
  5182. term->blink_is_real = term->blinktext;
  5183. term_schedule_tblink(term);
  5184. break;
  5185. #if 0
  5186. case '^':
  5187. /* XXX Enter auto print mode */
  5188. break;
  5189. case '_':
  5190. /* XXX Exit auto print mode */
  5191. break;
  5192. case ']':
  5193. /* XXX Print screen */
  5194. break;
  5195. #endif
  5196. #ifdef VT52_PLUS
  5197. case 'E':
  5198. /* compatibility(ATARI) */
  5199. move(term, 0, 0, 0);
  5200. erase_lots(term, false, false, true);
  5201. if (term->scroll_on_disp)
  5202. term->disptop = 0;
  5203. break;
  5204. case 'L':
  5205. /* compatibility(ATARI) */
  5206. if (term->curs.y <= term->marg_b)
  5207. scroll(term, term->curs.y, term->marg_b, -1, false);
  5208. break;
  5209. case 'M':
  5210. /* compatibility(ATARI) */
  5211. if (term->curs.y <= term->marg_b)
  5212. scroll(term, term->curs.y, term->marg_b, 1, true);
  5213. break;
  5214. case 'b':
  5215. /* compatibility(ATARI) */
  5216. term->termstate = VT52_FG;
  5217. break;
  5218. case 'c':
  5219. /* compatibility(ATARI) */
  5220. term->termstate = VT52_BG;
  5221. break;
  5222. case 'd':
  5223. /* compatibility(ATARI) */
  5224. erase_lots(term, false, true, false);
  5225. if (term->scroll_on_disp)
  5226. term->disptop = 0;
  5227. break;
  5228. case 'e':
  5229. /* compatibility(ATARI) */
  5230. term->cursor_on = true;
  5231. seen_disp_event(term);
  5232. break;
  5233. case 'f':
  5234. /* compatibility(ATARI) */
  5235. term->cursor_on = false;
  5236. seen_disp_event(term);
  5237. break;
  5238. /* case 'j': Save cursor position - broken on ST */
  5239. /* case 'k': Restore cursor position */
  5240. case 'l':
  5241. /* compatibility(ATARI) */
  5242. erase_lots(term, true, true, true);
  5243. term->curs.x = 0;
  5244. term->wrapnext = false;
  5245. break;
  5246. case 'o':
  5247. /* compatibility(ATARI) */
  5248. erase_lots(term, true, true, false);
  5249. break;
  5250. case 'p':
  5251. /* compatibility(ATARI) */
  5252. term->curr_attr |= ATTR_REVERSE;
  5253. break;
  5254. case 'q':
  5255. /* compatibility(ATARI) */
  5256. term->curr_attr &= ~ATTR_REVERSE;
  5257. break;
  5258. case 'v': /* wrap Autowrap on - Wyse style */
  5259. /* compatibility(ATARI) */
  5260. term->wrap = true;
  5261. break;
  5262. case 'w': /* Autowrap off */
  5263. /* compatibility(ATARI) */
  5264. term->wrap = false;
  5265. term->wrapnext = false;
  5266. break;
  5267. case 'R':
  5268. /* compatibility(OTHER) */
  5269. term->vt52_bold = false;
  5270. term->curr_attr = ATTR_DEFAULT;
  5271. term->curr_truecolour.fg = optionalrgb_none;
  5272. term->curr_truecolour.bg = optionalrgb_none;
  5273. set_erase_char(term);
  5274. break;
  5275. case 'S':
  5276. /* compatibility(VI50) */
  5277. term->curr_attr |= ATTR_UNDER;
  5278. break;
  5279. case 'W':
  5280. /* compatibility(VI50) */
  5281. term->curr_attr &= ~ATTR_UNDER;
  5282. break;
  5283. case 'U':
  5284. /* compatibility(VI50) */
  5285. term->vt52_bold = true;
  5286. term->curr_attr |= ATTR_BOLD;
  5287. break;
  5288. case 'T':
  5289. /* compatibility(VI50) */
  5290. term->vt52_bold = false;
  5291. term->curr_attr &= ~ATTR_BOLD;
  5292. break;
  5293. #endif
  5294. }
  5295. break;
  5296. case VT52_Y1:
  5297. term->termstate = VT52_Y2;
  5298. move(term, term->curs.x, c - ' ', 0);
  5299. break;
  5300. case VT52_Y2:
  5301. term->termstate = TOPLEVEL;
  5302. move(term, c - ' ', term->curs.y, 0);
  5303. break;
  5304. #ifdef VT52_PLUS
  5305. case VT52_FG:
  5306. term->termstate = TOPLEVEL;
  5307. term->curr_attr &= ~ATTR_FGMASK;
  5308. term->curr_attr &= ~ATTR_BOLD;
  5309. term->curr_attr |= (c & 0xF) << ATTR_FGSHIFT;
  5310. set_erase_char(term);
  5311. break;
  5312. case VT52_BG:
  5313. term->termstate = TOPLEVEL;
  5314. term->curr_attr &= ~ATTR_BGMASK;
  5315. term->curr_attr &= ~ATTR_BLINK;
  5316. term->curr_attr |= (c & 0xF) << ATTR_BGSHIFT;
  5317. set_erase_char(term);
  5318. break;
  5319. #endif
  5320. default: break; /* placate gcc warning about enum use */
  5321. }
  5322. if (term->selstate != NO_SELECTION) {
  5323. pos cursplus = term->curs;
  5324. incpos(cursplus);
  5325. check_selection(term, term->curs, cursplus);
  5326. }
  5327. }
  5328. bufchain_consume(&term->inbuf, nchars_used);
  5329. if (!called_from_term_data)
  5330. win_unthrottle(term->win, bufchain_size(&term->inbuf));
  5331. term_print_flush(term);
  5332. if (term->logflush && term->logctx)
  5333. logflush(term->logctx);
  5334. }
  5335. /* Wrapper on term_out with the right prototype to be a toplevel callback */
  5336. void term_out_cb(void *ctx)
  5337. {
  5338. term_out((Terminal *)ctx, false);
  5339. }
  5340. /*
  5341. * Small subroutine to parse three consecutive escape-sequence
  5342. * arguments representing a true-colour RGB triple into an
  5343. * optionalrgb.
  5344. */
  5345. static void parse_optionalrgb(optionalrgb *out, unsigned *values)
  5346. {
  5347. out->enabled = true;
  5348. out->r = values[0] < 256 ? values[0] : 0;
  5349. out->g = values[1] < 256 ? values[1] : 0;
  5350. out->b = values[2] < 256 ? values[2] : 0;
  5351. }
  5352. /*
  5353. * To prevent having to run the reasonably tricky bidi algorithm
  5354. * too many times, we maintain a cache of the last lineful of data
  5355. * fed to the algorithm on each line of the display.
  5356. */
  5357. static bool term_bidi_cache_hit(Terminal *term, int line,
  5358. termchar *lbefore, int width, bool trusted)
  5359. {
  5360. int i;
  5361. if (!term->pre_bidi_cache)
  5362. return false; /* cache doesn't even exist yet! */
  5363. if (line >= term->bidi_cache_size)
  5364. return false; /* cache doesn't have this many lines */
  5365. if (!term->pre_bidi_cache[line].chars)
  5366. return false; /* cache doesn't contain _this_ line */
  5367. if (term->pre_bidi_cache[line].width != width)
  5368. return false; /* line is wrong width */
  5369. if (term->pre_bidi_cache[line].trusted != trusted)
  5370. return false; /* line has wrong trust state */
  5371. for (i = 0; i < width; i++)
  5372. if (!termchars_equal(term->pre_bidi_cache[line].chars+i, lbefore+i))
  5373. return false; /* line doesn't match cache */
  5374. return true; /* it didn't match. */
  5375. }
  5376. static void term_bidi_cache_store(Terminal *term, int line, termchar *lbefore,
  5377. termchar *lafter, bidi_char *wcTo,
  5378. int width, int size, bool trusted)
  5379. {
  5380. size_t i, j;
  5381. if (!term->pre_bidi_cache || term->bidi_cache_size <= line) {
  5382. j = term->bidi_cache_size;
  5383. sgrowarray(term->pre_bidi_cache, term->bidi_cache_size, line);
  5384. term->post_bidi_cache = sresize(term->post_bidi_cache,
  5385. term->bidi_cache_size,
  5386. struct bidi_cache_entry);
  5387. while (j < term->bidi_cache_size) {
  5388. term->pre_bidi_cache[j].chars =
  5389. term->post_bidi_cache[j].chars = NULL;
  5390. term->pre_bidi_cache[j].width =
  5391. term->post_bidi_cache[j].width = -1;
  5392. term->pre_bidi_cache[j].trusted = false;
  5393. term->post_bidi_cache[j].trusted = false;
  5394. term->pre_bidi_cache[j].forward =
  5395. term->post_bidi_cache[j].forward = NULL;
  5396. term->pre_bidi_cache[j].backward =
  5397. term->post_bidi_cache[j].backward = NULL;
  5398. j++;
  5399. }
  5400. }
  5401. sfree(term->pre_bidi_cache[line].chars);
  5402. sfree(term->post_bidi_cache[line].chars);
  5403. sfree(term->post_bidi_cache[line].forward);
  5404. sfree(term->post_bidi_cache[line].backward);
  5405. term->pre_bidi_cache[line].width = width;
  5406. term->pre_bidi_cache[line].trusted = trusted;
  5407. term->pre_bidi_cache[line].chars = snewn(size, termchar);
  5408. term->post_bidi_cache[line].width = width;
  5409. term->post_bidi_cache[line].trusted = trusted;
  5410. term->post_bidi_cache[line].chars = snewn(size, termchar);
  5411. term->post_bidi_cache[line].forward = snewn(width, int);
  5412. term->post_bidi_cache[line].backward = snewn(width, int);
  5413. memcpy(term->pre_bidi_cache[line].chars, lbefore, size * TSIZE);
  5414. memcpy(term->post_bidi_cache[line].chars, lafter, size * TSIZE);
  5415. memset(term->post_bidi_cache[line].forward, 0, width * sizeof(int));
  5416. memset(term->post_bidi_cache[line].backward, 0, width * sizeof(int));
  5417. for (i = j = 0; j < width; j += wcTo[i].nchars, i++) {
  5418. int p = wcTo[i].index;
  5419. if (p != BIDI_CHAR_INDEX_NONE) {
  5420. assert(0 <= p && p < width);
  5421. for (int x = 0; x < wcTo[i].nchars; x++) {
  5422. term->post_bidi_cache[line].backward[j+x] = p+x;
  5423. term->post_bidi_cache[line].forward[p+x] = j+x;
  5424. }
  5425. }
  5426. }
  5427. }
  5428. /*
  5429. * Prepare the bidi information for a screen line. Returns the
  5430. * transformed list of termchars, or NULL if no transformation at
  5431. * all took place (because bidi is disabled). If return was
  5432. * non-NULL, auxiliary information such as the forward and reverse
  5433. * mappings of permutation position are available in
  5434. * term->post_bidi_cache[scr_y].*.
  5435. */
  5436. static termchar *term_bidi_line(Terminal *term, struct termline *ldata,
  5437. int scr_y)
  5438. {
  5439. termchar *lchars;
  5440. int it;
  5441. /* Do Arabic shaping and bidi. */
  5442. if (!term->no_bidi || !term->no_arabicshaping ||
  5443. (ldata->trusted && term->cols > TRUST_SIGIL_WIDTH)) {
  5444. if (!term_bidi_cache_hit(term, scr_y, ldata->chars, term->cols,
  5445. ldata->trusted)) {
  5446. if (term->wcFromTo_size < term->cols) {
  5447. term->wcFromTo_size = term->cols;
  5448. term->wcFrom = sresize(term->wcFrom, term->wcFromTo_size,
  5449. bidi_char);
  5450. term->wcTo = sresize(term->wcTo, term->wcFromTo_size,
  5451. bidi_char);
  5452. }
  5453. for (it=0; it<term->cols ; it++) {
  5454. unsigned long uc = (ldata->chars[it].chr);
  5455. switch (uc & CSET_MASK) {
  5456. case CSET_LINEDRW:
  5457. if (!term->rawcnp) {
  5458. uc = term->ucsdata->unitab_xterm[uc & 0xFF];
  5459. break;
  5460. }
  5461. case CSET_ASCII:
  5462. uc = term->ucsdata->unitab_line[uc & 0xFF];
  5463. break;
  5464. case CSET_SCOACS:
  5465. uc = term->ucsdata->unitab_scoacs[uc&0xFF];
  5466. break;
  5467. }
  5468. switch (uc & CSET_MASK) {
  5469. case CSET_ACP:
  5470. uc = term->ucsdata->unitab_font[uc & 0xFF];
  5471. break;
  5472. case CSET_OEMCP:
  5473. uc = term->ucsdata->unitab_oemcp[uc & 0xFF];
  5474. break;
  5475. }
  5476. term->wcFrom[it].origwc = term->wcFrom[it].wc =
  5477. (unsigned int)uc;
  5478. term->wcFrom[it].index = it;
  5479. term->wcFrom[it].nchars = 1;
  5480. }
  5481. if (ldata->trusted && term->cols > TRUST_SIGIL_WIDTH) {
  5482. memmove(
  5483. term->wcFrom + TRUST_SIGIL_WIDTH, term->wcFrom,
  5484. (term->cols - TRUST_SIGIL_WIDTH) * sizeof(*term->wcFrom));
  5485. for (it = 0; it < TRUST_SIGIL_WIDTH; it++) {
  5486. term->wcFrom[it].origwc = term->wcFrom[it].wc =
  5487. (it == 0 ? TRUST_SIGIL_CHAR :
  5488. it == 1 ? UCSWIDE : ' ');
  5489. term->wcFrom[it].index = BIDI_CHAR_INDEX_NONE;
  5490. term->wcFrom[it].nchars = 1;
  5491. }
  5492. }
  5493. int nbc = 0;
  5494. for (it = 0; it < term->cols; it++) {
  5495. term->wcFrom[nbc] = term->wcFrom[it];
  5496. if (it+1 < term->cols && term->wcFrom[it+1].wc == UCSWIDE) {
  5497. term->wcFrom[nbc].nchars++;
  5498. it++;
  5499. }
  5500. nbc++;
  5501. }
  5502. if (!term->no_bidi)
  5503. do_bidi(term->bidi_ctx, term->wcFrom, nbc);
  5504. if (!term->no_arabicshaping) {
  5505. do_shape(term->wcFrom, term->wcTo, nbc);
  5506. } else {
  5507. /* If we're not calling do_shape, we must copy the
  5508. * data into wcTo anyway, unchanged */
  5509. memcpy(term->wcTo, term->wcFrom, nbc * sizeof(*term->wcTo));
  5510. }
  5511. if (term->ltemp_size < ldata->size) {
  5512. term->ltemp_size = ldata->size;
  5513. term->ltemp = sresize(term->ltemp, term->ltemp_size,
  5514. termchar);
  5515. }
  5516. memcpy(term->ltemp, ldata->chars, ldata->size * TSIZE);
  5517. int opos = 0;
  5518. for (it=0; it<nbc; it++) {
  5519. int ipos = term->wcTo[it].index;
  5520. for (int j = 0; j < term->wcTo[it].nchars; j++) {
  5521. if (ipos != BIDI_CHAR_INDEX_NONE) {
  5522. term->ltemp[opos] = ldata->chars[ipos];
  5523. if (term->ltemp[opos].cc_next)
  5524. term->ltemp[opos].cc_next -= opos - ipos;
  5525. if (j > 0)
  5526. term->ltemp[opos].chr = UCSWIDE;
  5527. else if (term->wcTo[it].origwc != term->wcTo[it].wc)
  5528. term->ltemp[opos].chr = term->wcTo[it].wc;
  5529. } else {
  5530. term->ltemp[opos] = term->basic_erase_char;
  5531. term->ltemp[opos].chr =
  5532. j > 0 ? UCSWIDE : term->wcTo[it].origwc;
  5533. }
  5534. opos++;
  5535. }
  5536. }
  5537. assert(opos == term->cols);
  5538. term_bidi_cache_store(term, scr_y, ldata->chars,
  5539. term->ltemp, term->wcTo,
  5540. term->cols, ldata->size, ldata->trusted);
  5541. lchars = term->ltemp;
  5542. } else {
  5543. lchars = term->post_bidi_cache[scr_y].chars;
  5544. }
  5545. } else {
  5546. lchars = NULL;
  5547. }
  5548. return lchars;
  5549. }
  5550. static void do_paint_draw(Terminal *term, termline *ldata, int x, int y,
  5551. wchar_t *ch, int ccount,
  5552. unsigned long attr, truecolour tc)
  5553. {
  5554. if (ch[0] == TRUST_SIGIL_CHAR) {
  5555. assert(ldata->trusted);
  5556. assert(ccount == 1);
  5557. assert(attr & ATTR_WIDE);
  5558. wchar_t tch[2];
  5559. tch[0] = tch[1] = L' ';
  5560. win_draw_text(term->win, x, y, tch, 2, term->basic_erase_char.attr,
  5561. ldata->lattr, term->basic_erase_char.truecolour);
  5562. win_draw_trust_sigil(term->win, x, y);
  5563. } else {
  5564. if (ccount == 2 &&
  5565. IS_REGIONAL_INDICATOR_LETTER(ch[0]) &&
  5566. IS_REGIONAL_INDICATOR_LETTER(ch[1]))
  5567. attr |= ATTR_WIDE | TATTR_COMBINING;
  5568. win_draw_text(term->win, x, y, ch, ccount, attr, ldata->lattr, tc);
  5569. if (attr & (TATTR_ACTCURS | TATTR_PASCURS))
  5570. win_draw_cursor(term->win, x, y, ch, ccount,
  5571. attr, ldata->lattr, tc);
  5572. }
  5573. }
  5574. /*
  5575. * Given a context, update the window.
  5576. */
  5577. static void do_paint(Terminal *term)
  5578. {
  5579. int i, j, our_curs_y, our_curs_x;
  5580. int rv, cursor;
  5581. pos scrpos;
  5582. wchar_t *ch;
  5583. size_t chlen;
  5584. termchar *newline;
  5585. chlen = 1024;
  5586. ch = snewn(chlen, wchar_t);
  5587. newline = snewn(term->cols, termchar);
  5588. rv = (!term->rvideo ^ !term->in_vbell ? ATTR_REVERSE : 0);
  5589. /* Depends on:
  5590. * screen array, disptop, scrtop,
  5591. * selection, rv,
  5592. * blinkpc, blink_is_real, tblinker,
  5593. * curs.y, curs.x, cblinker, blink_cur, cursor_on, has_focus, wrapnext
  5594. */
  5595. /* Has the cursor position or type changed ? */
  5596. if (term->cursor_on) {
  5597. if (term->has_focus) {
  5598. if (term->cblinker || !term->blink_cur)
  5599. cursor = TATTR_ACTCURS;
  5600. else
  5601. cursor = 0;
  5602. } else
  5603. cursor = TATTR_PASCURS;
  5604. if (term->wrapnext)
  5605. cursor |= TATTR_RIGHTCURS;
  5606. } else
  5607. cursor = 0;
  5608. our_curs_y = term->curs.y - term->disptop;
  5609. {
  5610. /*
  5611. * Adjust the cursor position:
  5612. * - for bidi
  5613. * - in the case where it's resting on the right-hand half
  5614. * of a CJK wide character. xterm's behaviour here,
  5615. * which seems adequate to me, is to display the cursor
  5616. * covering the _whole_ character, exactly as if it were
  5617. * one space to the left.
  5618. */
  5619. termline *ldata = lineptr(term->curs.y);
  5620. termchar *lchars;
  5621. our_curs_x = term->curs.x;
  5622. if ( (lchars = term_bidi_line(term, ldata, our_curs_y)) != NULL) {
  5623. our_curs_x = term->post_bidi_cache[our_curs_y].forward[our_curs_x];
  5624. } else
  5625. lchars = ldata->chars;
  5626. if (our_curs_x > 0 &&
  5627. lchars[our_curs_x].chr == UCSWIDE)
  5628. our_curs_x--;
  5629. unlineptr(ldata);
  5630. }
  5631. /*
  5632. * If the cursor is not where it was last time we painted, and
  5633. * its previous position is visible on screen, invalidate its
  5634. * previous position.
  5635. */
  5636. if (term->dispcursy >= 0 &&
  5637. (term->curstype != cursor ||
  5638. term->dispcursy != our_curs_y ||
  5639. term->dispcursx != our_curs_x)) {
  5640. termchar *dispcurs = term->disptext[term->dispcursy]->chars +
  5641. term->dispcursx;
  5642. if (term->dispcursx > 0 && dispcurs->chr == UCSWIDE)
  5643. dispcurs[-1].attr |= ATTR_INVALID;
  5644. if (term->dispcursx < term->cols-1 && dispcurs[1].chr == UCSWIDE)
  5645. dispcurs[1].attr |= ATTR_INVALID;
  5646. dispcurs->attr |= ATTR_INVALID;
  5647. term->curstype = 0;
  5648. }
  5649. term->dispcursx = term->dispcursy = -1;
  5650. /* The normal screen data */
  5651. for (i = 0; i < term->rows; i++) {
  5652. termline *ldata;
  5653. termchar *lchars;
  5654. bool dirty_line, dirty_run, selected;
  5655. unsigned long attr = 0, cset = 0;
  5656. int start = 0;
  5657. int ccount = 0;
  5658. bool last_run_dirty = false;
  5659. int laststart;
  5660. bool dirtyrect;
  5661. int *backward;
  5662. truecolour tc;
  5663. scrpos.y = i + term->disptop;
  5664. ldata = lineptr(scrpos.y);
  5665. /* Do Arabic shaping and bidi. */
  5666. lchars = term_bidi_line(term, ldata, i);
  5667. if (lchars) {
  5668. backward = term->post_bidi_cache[i].backward;
  5669. } else {
  5670. lchars = ldata->chars;
  5671. backward = NULL;
  5672. }
  5673. /*
  5674. * First loop: work along the line deciding what we want
  5675. * each character cell to look like.
  5676. */
  5677. for (j = 0; j < term->cols; j++) {
  5678. unsigned long tattr, tchar;
  5679. termchar *d = lchars + j;
  5680. scrpos.x = backward ? backward[j] : j;
  5681. tchar = d->chr;
  5682. tattr = d->attr;
  5683. if (!term->ansi_colour)
  5684. tattr = (tattr & ~(ATTR_FGMASK | ATTR_BGMASK)) |
  5685. ATTR_DEFFG | ATTR_DEFBG;
  5686. if (!term->xterm_256_colour) {
  5687. int colour;
  5688. colour = (tattr & ATTR_FGMASK) >> ATTR_FGSHIFT;
  5689. if (colour >= 16 && colour < 256)
  5690. tattr = (tattr &~ ATTR_FGMASK) | ATTR_DEFFG;
  5691. colour = (tattr & ATTR_BGMASK) >> ATTR_BGSHIFT;
  5692. if (colour >= 16 && colour < 256)
  5693. tattr = (tattr &~ ATTR_BGMASK) | ATTR_DEFBG;
  5694. }
  5695. if (term->true_colour) {
  5696. tc = d->truecolour;
  5697. } else {
  5698. tc.fg = tc.bg = optionalrgb_none;
  5699. }
  5700. switch (tchar & CSET_MASK) {
  5701. case CSET_ASCII:
  5702. tchar = term->ucsdata->unitab_line[tchar & 0xFF];
  5703. break;
  5704. case CSET_LINEDRW:
  5705. tchar = term->ucsdata->unitab_xterm[tchar & 0xFF];
  5706. break;
  5707. case CSET_SCOACS:
  5708. tchar = term->ucsdata->unitab_scoacs[tchar&0xFF];
  5709. break;
  5710. }
  5711. if (j < term->cols-1 && d[1].chr == UCSWIDE)
  5712. tattr |= ATTR_WIDE;
  5713. /* Video reversing things */
  5714. if (term->selstate == DRAGGING || term->selstate == SELECTED) {
  5715. if (term->seltype == LEXICOGRAPHIC)
  5716. selected = (posle(term->selstart, scrpos) &&
  5717. poslt(scrpos, term->selend));
  5718. else
  5719. selected = (posPle(term->selstart, scrpos) &&
  5720. posPle_left(scrpos, term->selend));
  5721. } else
  5722. selected = false;
  5723. tattr = (tattr ^ rv
  5724. ^ (selected ? ATTR_REVERSE : 0));
  5725. /* 'Real' blinking ? */
  5726. if (term->blink_is_real && (tattr & ATTR_BLINK)) {
  5727. if (term->has_focus && term->tblinker) {
  5728. tchar = term->ucsdata->unitab_line[(unsigned char)' '];
  5729. }
  5730. tattr &= ~ATTR_BLINK;
  5731. }
  5732. /*
  5733. * Check the font we'll _probably_ be using to see if
  5734. * the character is wide when we don't want it to be.
  5735. */
  5736. if (tchar != term->disptext[i]->chars[j].chr ||
  5737. tattr != (term->disptext[i]->chars[j].attr &~
  5738. (ATTR_NARROW | DATTR_MASK))) {
  5739. if ((tattr & ATTR_WIDE) == 0 &&
  5740. win_char_width(term->win, tchar) == 2)
  5741. tattr |= ATTR_NARROW;
  5742. } else if (term->disptext[i]->chars[j].attr & ATTR_NARROW)
  5743. tattr |= ATTR_NARROW;
  5744. if (i == our_curs_y && j == our_curs_x) {
  5745. tattr |= cursor;
  5746. term->curstype = cursor;
  5747. term->dispcursx = j;
  5748. term->dispcursy = i;
  5749. }
  5750. /* FULL-TERMCHAR */
  5751. newline[j].attr = tattr;
  5752. newline[j].chr = tchar;
  5753. newline[j].truecolour = tc;
  5754. /* Combining characters are still read from lchars */
  5755. newline[j].cc_next = 0;
  5756. }
  5757. /*
  5758. * Now loop over the line again, noting where things have
  5759. * changed.
  5760. *
  5761. * During this loop, we keep track of where we last saw
  5762. * DATTR_STARTRUN. Any mismatch automatically invalidates
  5763. * _all_ of the containing run that was last printed: that
  5764. * is, any rectangle that was drawn in one go in the
  5765. * previous update should be either left completely alone
  5766. * or overwritten in its entirety. This, along with the
  5767. * expectation that front ends clip all text runs to their
  5768. * bounding rectangle, should solve any possible problems
  5769. * with fonts that overflow their character cells.
  5770. */
  5771. laststart = 0;
  5772. dirtyrect = false;
  5773. for (j = 0; j < term->cols; j++) {
  5774. if (term->disptext[i]->chars[j].attr & DATTR_STARTRUN) {
  5775. laststart = j;
  5776. dirtyrect = false;
  5777. }
  5778. if (term->disptext[i]->chars[j].chr != newline[j].chr ||
  5779. (term->disptext[i]->chars[j].attr &~ DATTR_MASK)
  5780. != newline[j].attr) {
  5781. int k;
  5782. if (!dirtyrect) {
  5783. for (k = laststart; k < j; k++)
  5784. term->disptext[i]->chars[k].attr |= ATTR_INVALID;
  5785. dirtyrect = true;
  5786. }
  5787. }
  5788. if (dirtyrect)
  5789. term->disptext[i]->chars[j].attr |= ATTR_INVALID;
  5790. }
  5791. /*
  5792. * Finally, loop once more and actually do the drawing.
  5793. */
  5794. dirty_run = dirty_line = (ldata->lattr !=
  5795. term->disptext[i]->lattr);
  5796. term->disptext[i]->lattr = ldata->lattr;
  5797. tc = term->erase_char.truecolour;
  5798. for (j = 0; j < term->cols; j++) {
  5799. unsigned long tattr, tchar;
  5800. bool break_run, do_copy, next_run_dirty = false;
  5801. termchar *d = lchars + j;
  5802. tattr = newline[j].attr;
  5803. tchar = newline[j].chr;
  5804. if ((term->disptext[i]->chars[j].attr ^ tattr) & ATTR_WIDE)
  5805. dirty_line = true;
  5806. break_run = ((tattr ^ attr) & term->attr_mask) != 0;
  5807. if (!truecolour_equal(newline[j].truecolour, tc))
  5808. break_run = true;
  5809. #ifdef USES_VTLINE_HACK
  5810. /* Special hack for VT100 Linedraw glyphs */
  5811. if ((tchar >= 0x23BA && tchar <= 0x23BD) ||
  5812. (j > 0 && (newline[j-1].chr >= 0x23BA &&
  5813. newline[j-1].chr <= 0x23BD)))
  5814. break_run = true;
  5815. #endif
  5816. /*
  5817. * Separate out sequences of characters that have the
  5818. * same CSET, if that CSET is a magic one.
  5819. */
  5820. if (CSET_OF(tchar) != cset)
  5821. break_run = true;
  5822. /*
  5823. * Break on both sides of any combined-character cell.
  5824. */
  5825. if (d->cc_next != 0 ||
  5826. (j > 0 && d[-1].cc_next != 0))
  5827. break_run = true;
  5828. /*
  5829. * Break on both sides of a regional indicator letter.
  5830. */
  5831. if (IS_REGIONAL_INDICATOR_LETTER(tchar)) {
  5832. break_run = true;
  5833. if (j+1 < term->cols) {
  5834. /* Also, check if there are any changes to whether or
  5835. * not we're drawing this and the next character as a
  5836. * single flag glyph. */
  5837. bool flag_now = IS_REGIONAL_INDICATOR_LETTER(d[1].chr);
  5838. bool flag_before = (
  5839. IS_REGIONAL_INDICATOR_LETTER(
  5840. term->disptext[i]->chars[j].chr) &&
  5841. IS_REGIONAL_INDICATOR_LETTER(
  5842. term->disptext[i]->chars[j+1].chr) &&
  5843. (term->disptext[i]->chars[j].attr & DATTR_STARTRUN));
  5844. if (flag_now != flag_before)
  5845. next_run_dirty = true; /* must redraw this flag */
  5846. }
  5847. } else if (j>0 && IS_REGIONAL_INDICATOR_LETTER(d[-1].chr)) {
  5848. break_run = true;
  5849. }
  5850. /*
  5851. * Break on both sides of a trust sigil.
  5852. */
  5853. if (d->chr == TRUST_SIGIL_CHAR ||
  5854. (j >= 2 && d[-1].chr == UCSWIDE &&
  5855. d[-2].chr == TRUST_SIGIL_CHAR))
  5856. break_run = true;
  5857. if (!term->ucsdata->dbcs_screenfont && !dirty_line) {
  5858. if (term->disptext[i]->chars[j].chr == tchar &&
  5859. (term->disptext[i]->chars[j].attr &~ DATTR_MASK)==tattr &&
  5860. truecolour_equal(
  5861. term->disptext[i]->chars[j].truecolour, tc))
  5862. break_run = true;
  5863. else if (!dirty_run && ccount == 1)
  5864. break_run = true;
  5865. }
  5866. if (break_run) {
  5867. if ((dirty_run || last_run_dirty) && ccount > 0)
  5868. do_paint_draw(term, ldata, start, i, ch, ccount, attr, tc);
  5869. start = j;
  5870. ccount = 0;
  5871. attr = tattr;
  5872. tc = newline[j].truecolour;
  5873. cset = CSET_OF(tchar);
  5874. if (term->ucsdata->dbcs_screenfont)
  5875. last_run_dirty = dirty_run;
  5876. dirty_run = dirty_line || next_run_dirty;
  5877. }
  5878. do_copy = false;
  5879. if (!termchars_equal_override(&term->disptext[i]->chars[j],
  5880. d, tchar, tattr)) {
  5881. do_copy = true;
  5882. dirty_run = true;
  5883. }
  5884. sgrowarrayn(ch, chlen, ccount, 2);
  5885. #ifdef PLATFORM_IS_UTF16
  5886. if (tchar > 0x10000 && tchar < 0x110000) {
  5887. ch[ccount++] = (wchar_t) HIGH_SURROGATE_OF(tchar);
  5888. ch[ccount++] = (wchar_t) LOW_SURROGATE_OF(tchar);
  5889. } else
  5890. #endif /* PLATFORM_IS_UTF16 */
  5891. ch[ccount++] = (wchar_t) tchar;
  5892. if (d->cc_next) {
  5893. termchar *dd = d;
  5894. while (dd->cc_next) {
  5895. unsigned long schar;
  5896. dd += dd->cc_next;
  5897. schar = dd->chr;
  5898. switch (schar & CSET_MASK) {
  5899. case CSET_ASCII:
  5900. schar = term->ucsdata->unitab_line[schar & 0xFF];
  5901. break;
  5902. case CSET_LINEDRW:
  5903. schar = term->ucsdata->unitab_xterm[schar & 0xFF];
  5904. break;
  5905. case CSET_SCOACS:
  5906. schar = term->ucsdata->unitab_scoacs[schar&0xFF];
  5907. break;
  5908. }
  5909. sgrowarrayn(ch, chlen, ccount, 2);
  5910. #ifdef PLATFORM_IS_UTF16
  5911. if (schar > 0x10000 && schar < 0x110000) {
  5912. ch[ccount++] = (wchar_t) HIGH_SURROGATE_OF(schar);
  5913. ch[ccount++] = (wchar_t) LOW_SURROGATE_OF(schar);
  5914. } else
  5915. #endif /* PLATFORM_IS_UTF16 */
  5916. ch[ccount++] = (wchar_t) schar;
  5917. }
  5918. attr |= TATTR_COMBINING;
  5919. }
  5920. if (do_copy) {
  5921. copy_termchar(term->disptext[i], j, d);
  5922. term->disptext[i]->chars[j].chr = tchar;
  5923. term->disptext[i]->chars[j].attr = tattr;
  5924. term->disptext[i]->chars[j].truecolour = tc;
  5925. if (start == j)
  5926. term->disptext[i]->chars[j].attr |= DATTR_STARTRUN;
  5927. }
  5928. /* If it's a wide char step along to the next one. */
  5929. if (tattr & ATTR_WIDE) {
  5930. if (++j < term->cols) {
  5931. d++;
  5932. /*
  5933. * By construction above, the cursor should not
  5934. * be on the right-hand half of this character.
  5935. * Ever.
  5936. */
  5937. assert(!(i == our_curs_y && j == our_curs_x));
  5938. if (!termchars_equal(&term->disptext[i]->chars[j], d))
  5939. dirty_run = true;
  5940. copy_termchar(term->disptext[i], j, d);
  5941. }
  5942. }
  5943. /* If it's a regional indicator letter, and so is the next
  5944. * one, then also step to the next one, keeping the flag
  5945. * sequence together. */
  5946. if (IS_REGIONAL_INDICATOR_LETTER(d->chr) &&
  5947. (j+1 < term->cols && IS_REGIONAL_INDICATOR_LETTER(d[1].chr))) {
  5948. j++;
  5949. d++;
  5950. /* Set ATTR_WIDE, so that the pair is displayed as one */
  5951. attr |= ATTR_WIDE;
  5952. /* Include the second letter in the text buffer */
  5953. unsigned long rchar = d->chr;
  5954. #ifdef PLATFORM_IS_UTF16
  5955. sgrowarrayn(ch, chlen, ccount, 2);
  5956. ch[ccount++] = (wchar_t)HIGH_SURROGATE_OF(rchar);
  5957. ch[ccount++] = (wchar_t)LOW_SURROGATE_OF(rchar);
  5958. #else
  5959. sgrowarrayn(ch, chlen, ccount, 1);
  5960. ch[ccount++] = (wchar_t)rchar;
  5961. #endif
  5962. /* Display the cursor, if it's on the right half */
  5963. if (i == our_curs_y && j == our_curs_x) {
  5964. attr |= cursor;
  5965. term->disptext[i]->chars[j-1].attr |= cursor;
  5966. }
  5967. if (!termchars_equal_override(
  5968. &term->disptext[i]->chars[j],
  5969. d, rchar, term->disptext[i]->chars[j-1].attr))
  5970. dirty_run = true;
  5971. copy_termchar(term->disptext[i], j, d);
  5972. term->disptext[i]->chars[j].attr =
  5973. term->disptext[i]->chars[j-1].attr & ~DATTR_STARTRUN;
  5974. }
  5975. }
  5976. if (dirty_run && ccount > 0)
  5977. do_paint_draw(term, ldata, start, i, ch, ccount, attr, tc);
  5978. unlineptr(ldata);
  5979. }
  5980. sfree(newline);
  5981. sfree(ch);
  5982. }
  5983. /*
  5984. * Invalidate the whole screen so it will be repainted in full.
  5985. */
  5986. void term_invalidate(Terminal *term)
  5987. {
  5988. int i, j;
  5989. for (i = 0; i < term->rows; i++)
  5990. for (j = 0; j < term->cols; j++)
  5991. term->disptext[i]->chars[j].attr |= ATTR_INVALID;
  5992. term_schedule_update(term);
  5993. }
  5994. /*
  5995. * Paint the window in response to a WM_PAINT message.
  5996. */
  5997. void term_paint(Terminal *term,
  5998. int left, int top, int right, int bottom, bool immediately)
  5999. {
  6000. int i, j;
  6001. if (left < 0) left = 0;
  6002. if (top < 0) top = 0;
  6003. if (right >= term->cols) right = term->cols-1;
  6004. if (bottom >= term->rows) bottom = term->rows-1;
  6005. for (i = top; i <= bottom && i < term->rows; i++) {
  6006. if ((term->disptext[i]->lattr & LATTR_MODE) == LATTR_NORM)
  6007. for (j = left; j <= right && j < term->cols; j++)
  6008. term->disptext[i]->chars[j].attr |= ATTR_INVALID;
  6009. else
  6010. for (j = left / 2; j <= right / 2 + 1 && j < term->cols; j++)
  6011. term->disptext[i]->chars[j].attr |= ATTR_INVALID;
  6012. }
  6013. if (immediately) {
  6014. do_paint(term);
  6015. } else {
  6016. term_schedule_update(term);
  6017. }
  6018. }
  6019. /*
  6020. * Attempt to scroll the scrollback. The second parameter gives the
  6021. * position we want to scroll to; the first is +1 to denote that
  6022. * this position is relative to the beginning of the scrollback, -1
  6023. * to denote it is relative to the end, and 0 to denote that it is
  6024. * relative to the current position.
  6025. */
  6026. void term_scroll(Terminal *term, int rel, int where)
  6027. {
  6028. int sbtop = -sblines(term);
  6029. term->disptop = (rel < 0 ? 0 : rel > 0 ? sbtop : term->disptop) + where;
  6030. if (term->disptop < sbtop)
  6031. term->disptop = sbtop;
  6032. if (term->disptop > 0)
  6033. term->disptop = 0;
  6034. term->win_scrollbar_update_pending = true;
  6035. term_schedule_update(term);
  6036. }
  6037. /*
  6038. * Scroll the scrollback to centre it on the beginning or end of the
  6039. * current selection, if any.
  6040. */
  6041. void term_scroll_to_selection(Terminal *term, int which_end)
  6042. {
  6043. pos target;
  6044. int y;
  6045. int sbtop = -sblines(term);
  6046. if (term->selstate != SELECTED)
  6047. return;
  6048. if (which_end)
  6049. target = term->selend;
  6050. else
  6051. target = term->selstart;
  6052. y = target.y - term->rows/2;
  6053. if (y < sbtop)
  6054. y = sbtop;
  6055. else if (y > 0)
  6056. y = 0;
  6057. term_scroll(term, -1, y);
  6058. }
  6059. /*
  6060. * Helper routine for clipme(): growing buffer.
  6061. */
  6062. typedef struct {
  6063. size_t bufsize; /* amount of allocated space in textbuf/attrbuf */
  6064. size_t bufpos; /* amount of actual data */
  6065. wchar_t *textbuf; /* buffer for copied text */
  6066. wchar_t *textptr; /* = textbuf + bufpos (current insertion point) */
  6067. int *attrbuf; /* buffer for copied attributes */
  6068. int *attrptr; /* = attrbuf + bufpos */
  6069. truecolour *tcbuf; /* buffer for copied colours */
  6070. truecolour *tcptr; /* = tcbuf + bufpos */
  6071. } clip_workbuf;
  6072. static void clip_addchar(clip_workbuf *b, wchar_t chr, int attr, truecolour tc)
  6073. {
  6074. if (b->bufpos >= b->bufsize) {
  6075. sgrowarray(b->textbuf, b->bufsize, b->bufpos);
  6076. b->textptr = b->textbuf + b->bufpos;
  6077. b->attrbuf = sresize(b->attrbuf, b->bufsize, int);
  6078. b->attrptr = b->attrbuf + b->bufpos;
  6079. b->tcbuf = sresize(b->tcbuf, b->bufsize, truecolour);
  6080. b->tcptr = b->tcbuf + b->bufpos;
  6081. }
  6082. *b->textptr++ = chr;
  6083. *b->attrptr++ = attr;
  6084. *b->tcptr++ = tc;
  6085. b->bufpos++;
  6086. }
  6087. static void clipme(Terminal *term, pos top, pos bottom, bool rect, bool desel,
  6088. const int *clipboards, int n_clipboards)
  6089. {
  6090. clip_workbuf buf;
  6091. int old_top_x;
  6092. int attr;
  6093. truecolour tc;
  6094. buf.bufsize = 5120;
  6095. buf.bufpos = 0;
  6096. buf.textptr = buf.textbuf = snewn(buf.bufsize, wchar_t);
  6097. buf.attrptr = buf.attrbuf = snewn(buf.bufsize, int);
  6098. buf.tcptr = buf.tcbuf = snewn(buf.bufsize, truecolour);
  6099. old_top_x = top.x; /* needed for rect==1 */
  6100. while (poslt(top, bottom)) {
  6101. bool nl = false;
  6102. termline *ldata = lineptr(top.y);
  6103. pos nlpos;
  6104. /*
  6105. * nlpos will point at the maximum position on this line we
  6106. * should copy up to. So we start it at the end of the
  6107. * line...
  6108. */
  6109. nlpos.y = top.y;
  6110. nlpos.x = term->cols;
  6111. /*
  6112. * ... move it backwards if there's unused space at the end
  6113. * of the line (and also set `nl' if this is the case,
  6114. * because in normal selection mode this means we need a
  6115. * newline at the end)...
  6116. */
  6117. if (!(ldata->lattr & LATTR_WRAPPED)) {
  6118. while (nlpos.x &&
  6119. IS_SPACE_CHR(ldata->chars[nlpos.x - 1].chr) &&
  6120. !ldata->chars[nlpos.x - 1].cc_next &&
  6121. poslt(top, nlpos))
  6122. decpos(nlpos);
  6123. if (poslt(nlpos, bottom))
  6124. nl = true;
  6125. } else {
  6126. if (ldata->trusted) {
  6127. /* A wrapped line with a trust sigil on it terminates
  6128. * a few characters earlier. */
  6129. nlpos.x = (nlpos.x < TRUST_SIGIL_WIDTH ? 0 :
  6130. nlpos.x - TRUST_SIGIL_WIDTH);
  6131. }
  6132. if (ldata->lattr & LATTR_WRAPPED2) {
  6133. /* Ignore the last char on the line in a WRAPPED2 line. */
  6134. decpos(nlpos);
  6135. }
  6136. }
  6137. /*
  6138. * ... and then clip it to the terminal x coordinate if
  6139. * we're doing rectangular selection. (In this case we
  6140. * still did the above, so that copying e.g. the right-hand
  6141. * column from a table doesn't fill with spaces on the
  6142. * right.)
  6143. */
  6144. if (rect) {
  6145. if (nlpos.x > bottom.x)
  6146. nlpos.x = bottom.x;
  6147. nl = (top.y < bottom.y);
  6148. }
  6149. while (poslt(top, bottom) && poslt(top, nlpos)) {
  6150. #if 0
  6151. char cbuf[16], *p;
  6152. sprintf(cbuf, "<U+%04x>", (ldata[top.x] & 0xFFFF));
  6153. #else
  6154. wchar_t cbuf[16], *p;
  6155. int c;
  6156. int x = top.x;
  6157. if (ldata->chars[x].chr == UCSWIDE) {
  6158. top.x++;
  6159. continue;
  6160. }
  6161. while (1) {
  6162. int uc = ldata->chars[x].chr;
  6163. attr = ldata->chars[x].attr;
  6164. tc = ldata->chars[x].truecolour;
  6165. switch (uc & CSET_MASK) {
  6166. case CSET_LINEDRW:
  6167. if (!term->rawcnp) {
  6168. uc = term->ucsdata->unitab_xterm[uc & 0xFF];
  6169. break;
  6170. }
  6171. case CSET_ASCII:
  6172. uc = term->ucsdata->unitab_line[uc & 0xFF];
  6173. break;
  6174. case CSET_SCOACS:
  6175. uc = term->ucsdata->unitab_scoacs[uc&0xFF];
  6176. break;
  6177. }
  6178. switch (uc & CSET_MASK) {
  6179. case CSET_ACP:
  6180. uc = term->ucsdata->unitab_font[uc & 0xFF];
  6181. break;
  6182. case CSET_OEMCP:
  6183. uc = term->ucsdata->unitab_oemcp[uc & 0xFF];
  6184. break;
  6185. }
  6186. c = (uc & ~CSET_MASK);
  6187. #ifdef PLATFORM_IS_UTF16
  6188. if (uc > 0x10000 && uc < 0x110000) {
  6189. cbuf[0] = 0xD800 | ((uc - 0x10000) >> 10);
  6190. cbuf[1] = 0xDC00 | ((uc - 0x10000) & 0x3FF);
  6191. cbuf[2] = 0;
  6192. } else
  6193. #endif
  6194. {
  6195. cbuf[0] = uc;
  6196. cbuf[1] = 0;
  6197. }
  6198. if (DIRECT_FONT(uc)) {
  6199. if (c >= ' ' && c != 0x7F) {
  6200. char buf[4];
  6201. WCHAR wbuf[4];
  6202. int rv;
  6203. if (is_dbcs_leadbyte(term->ucsdata->font_codepage, (BYTE) c)) {
  6204. buf[0] = c;
  6205. buf[1] = (char) (0xFF & ldata->chars[top.x + 1].chr);
  6206. rv = mb_to_wc(term->ucsdata->font_codepage, 0, buf, 2, wbuf, 4);
  6207. top.x++;
  6208. } else {
  6209. buf[0] = c;
  6210. rv = mb_to_wc(term->ucsdata->font_codepage, 0, buf, 1, wbuf, 4);
  6211. }
  6212. if (rv > 0) {
  6213. memcpy(cbuf, wbuf, rv * sizeof(wchar_t));
  6214. cbuf[rv] = 0;
  6215. }
  6216. }
  6217. }
  6218. #endif
  6219. for (p = cbuf; *p; p++)
  6220. clip_addchar(&buf, *p, attr, tc);
  6221. if (ldata->chars[x].cc_next)
  6222. x += ldata->chars[x].cc_next;
  6223. else
  6224. break;
  6225. }
  6226. top.x++;
  6227. }
  6228. if (nl) {
  6229. int i;
  6230. for (i = 0; i < sel_nl_sz; i++)
  6231. clip_addchar(&buf, sel_nl[i], 0, term->basic_erase_char.truecolour);
  6232. }
  6233. top.y++;
  6234. top.x = rect ? old_top_x : 0;
  6235. unlineptr(ldata);
  6236. }
  6237. #if SELECTION_NUL_TERMINATED
  6238. clip_addchar(&buf, 0, 0, term->basic_erase_char.truecolour);
  6239. #endif
  6240. /* Finally, transfer all that to the clipboard(s). */
  6241. {
  6242. int i;
  6243. bool clip_local = false;
  6244. for (i = 0; i < n_clipboards; i++) {
  6245. if (clipboards[i] == CLIP_LOCAL) {
  6246. clip_local = true;
  6247. } else if (clipboards[i] != CLIP_NULL) {
  6248. win_clip_write(
  6249. term->win, clipboards[i], buf.textbuf, buf.attrbuf,
  6250. buf.tcbuf, buf.bufpos, desel);
  6251. }
  6252. }
  6253. if (clip_local) {
  6254. sfree(term->last_selected_text);
  6255. sfree(term->last_selected_attr);
  6256. sfree(term->last_selected_tc);
  6257. term->last_selected_text = buf.textbuf;
  6258. term->last_selected_attr = buf.attrbuf;
  6259. term->last_selected_tc = buf.tcbuf;
  6260. term->last_selected_len = buf.bufpos;
  6261. } else {
  6262. sfree(buf.textbuf);
  6263. sfree(buf.attrbuf);
  6264. sfree(buf.tcbuf);
  6265. }
  6266. }
  6267. }
  6268. void term_copyall(Terminal *term, const int *clipboards, int n_clipboards)
  6269. {
  6270. pos top;
  6271. pos bottom;
  6272. tree234 *screen = term->screen;
  6273. top.y = -sblines(term);
  6274. top.x = 0;
  6275. bottom.y = find_last_nonempty_line(term, screen);
  6276. bottom.x = term->cols;
  6277. clipme(term, top, bottom, false, true, clipboards, n_clipboards);
  6278. }
  6279. static void paste_from_clip_local(void *vterm)
  6280. {
  6281. Terminal *term = (Terminal *)vterm;
  6282. term_do_paste(term, term->last_selected_text, term->last_selected_len);
  6283. }
  6284. void term_request_copy(Terminal *term, const int *clipboards, int n_clipboards)
  6285. {
  6286. int i;
  6287. for (i = 0; i < n_clipboards; i++) {
  6288. assert(clipboards[i] != CLIP_LOCAL);
  6289. if (clipboards[i] != CLIP_NULL) {
  6290. win_clip_write(term->win, clipboards[i],
  6291. term->last_selected_text, term->last_selected_attr,
  6292. term->last_selected_tc, term->last_selected_len,
  6293. false);
  6294. }
  6295. }
  6296. }
  6297. void term_request_paste(Terminal *term, int clipboard)
  6298. {
  6299. switch (clipboard) {
  6300. case CLIP_NULL:
  6301. /* Do nothing: CLIP_NULL never has data in it. */
  6302. break;
  6303. case CLIP_LOCAL:
  6304. queue_toplevel_callback(paste_from_clip_local, term);
  6305. break;
  6306. default:
  6307. win_clip_request_paste(term->win, clipboard);
  6308. break;
  6309. }
  6310. }
  6311. /*
  6312. * The wordness array is mainly for deciding the disposition of the
  6313. * US-ASCII characters.
  6314. */
  6315. static int wordtype(Terminal *term, int uc)
  6316. {
  6317. struct ucsword {
  6318. int start, end, ctype;
  6319. };
  6320. static const struct ucsword ucs_words[] = {
  6321. {128, 160, 0},
  6322. {161, 191, 1},
  6323. {215, 215, 1},
  6324. {247, 247, 1},
  6325. {0x037e, 0x037e, 1}, /* Greek question mark */
  6326. {0x0387, 0x0387, 1}, /* Greek ano teleia */
  6327. {0x055a, 0x055f, 1}, /* Armenian punctuation */
  6328. {0x0589, 0x0589, 1}, /* Armenian full stop */
  6329. {0x0700, 0x070d, 1}, /* Syriac punctuation */
  6330. {0x104a, 0x104f, 1}, /* Myanmar punctuation */
  6331. {0x10fb, 0x10fb, 1}, /* Georgian punctuation */
  6332. {0x1361, 0x1368, 1}, /* Ethiopic punctuation */
  6333. {0x166d, 0x166e, 1}, /* Canadian Syl. punctuation */
  6334. {0x17d4, 0x17dc, 1}, /* Khmer punctuation */
  6335. {0x1800, 0x180a, 1}, /* Mongolian punctuation */
  6336. {0x2000, 0x200a, 0}, /* Various spaces */
  6337. {0x2070, 0x207f, 2}, /* superscript */
  6338. {0x2080, 0x208f, 2}, /* subscript */
  6339. {0x200b, 0x27ff, 1}, /* punctuation and symbols */
  6340. {0x3000, 0x3000, 0}, /* ideographic space */
  6341. {0x3001, 0x3020, 1}, /* ideographic punctuation */
  6342. {0x303f, 0x309f, 3}, /* Hiragana */
  6343. {0x30a0, 0x30ff, 3}, /* Katakana */
  6344. {0x3300, 0x9fff, 3}, /* CJK Ideographs */
  6345. {0xac00, 0xd7a3, 3}, /* Hangul Syllables */
  6346. {0xf900, 0xfaff, 3}, /* CJK Ideographs */
  6347. {0xfe30, 0xfe6b, 1}, /* punctuation forms */
  6348. {0xff00, 0xff0f, 1}, /* half/fullwidth ASCII */
  6349. {0xff1a, 0xff20, 1}, /* half/fullwidth ASCII */
  6350. {0xff3b, 0xff40, 1}, /* half/fullwidth ASCII */
  6351. {0xff5b, 0xff64, 1}, /* half/fullwidth ASCII */
  6352. {0xfff0, 0xffff, 0}, /* half/fullwidth ASCII */
  6353. {0, 0, 0}
  6354. };
  6355. const struct ucsword *wptr;
  6356. switch (uc & CSET_MASK) {
  6357. case CSET_LINEDRW:
  6358. uc = term->ucsdata->unitab_xterm[uc & 0xFF];
  6359. break;
  6360. case CSET_ASCII:
  6361. uc = term->ucsdata->unitab_line[uc & 0xFF];
  6362. break;
  6363. case CSET_SCOACS:
  6364. uc = term->ucsdata->unitab_scoacs[uc&0xFF];
  6365. break;
  6366. }
  6367. switch (uc & CSET_MASK) {
  6368. case CSET_ACP:
  6369. uc = term->ucsdata->unitab_font[uc & 0xFF];
  6370. break;
  6371. case CSET_OEMCP:
  6372. uc = term->ucsdata->unitab_oemcp[uc & 0xFF];
  6373. break;
  6374. }
  6375. /* For DBCS fonts I can't do anything useful. Even this will sometimes
  6376. * fail as there's such a thing as a double width space. :-(
  6377. */
  6378. if (term->ucsdata->dbcs_screenfont &&
  6379. term->ucsdata->font_codepage == term->ucsdata->line_codepage)
  6380. return (uc != ' ');
  6381. if (uc < 0x80)
  6382. return term->wordness[uc];
  6383. for (wptr = ucs_words; wptr->start; wptr++) {
  6384. if (uc >= wptr->start && uc <= wptr->end)
  6385. return wptr->ctype;
  6386. }
  6387. return 2;
  6388. }
  6389. static int line_cols(Terminal *term, termline *ldata)
  6390. {
  6391. int cols = term->cols;
  6392. if (ldata->trusted) {
  6393. cols -= TRUST_SIGIL_WIDTH;
  6394. }
  6395. if (ldata->lattr & LATTR_WRAPPED2)
  6396. cols--;
  6397. if (cols < 0)
  6398. cols = 0;
  6399. return cols;
  6400. }
  6401. /*
  6402. * Spread the selection outwards according to the selection mode.
  6403. */
  6404. static pos sel_spread_half(Terminal *term, pos p, int dir)
  6405. {
  6406. termline *ldata;
  6407. short wvalue;
  6408. int topy = -sblines(term);
  6409. ldata = lineptr(p.y);
  6410. switch (term->selmode) {
  6411. case SM_CHAR:
  6412. /*
  6413. * In this mode, every character is a separate unit, except
  6414. * for runs of spaces at the end of a non-wrapping line.
  6415. */
  6416. if (!(ldata->lattr & LATTR_WRAPPED)) {
  6417. termchar *q = ldata->chars + line_cols(term, ldata);
  6418. while (q > ldata->chars &&
  6419. IS_SPACE_CHR(q[-1].chr) && !q[-1].cc_next)
  6420. q--;
  6421. if (q == ldata->chars + term->cols)
  6422. q--;
  6423. if (p.x >= q - ldata->chars)
  6424. p.x = (dir == -1 ? q - ldata->chars : term->cols - 1);
  6425. }
  6426. break;
  6427. case SM_WORD:
  6428. /*
  6429. * In this mode, the units are maximal runs of characters
  6430. * whose `wordness' has the same value.
  6431. */
  6432. wvalue = wordtype(term, UCSGET(ldata->chars, p.x));
  6433. if (dir == +1) {
  6434. while (1) {
  6435. int maxcols = line_cols(term, ldata);
  6436. if (p.x < maxcols-1) {
  6437. if (wordtype(term, UCSGET(ldata->chars, p.x+1)) == wvalue)
  6438. p.x++;
  6439. else
  6440. break;
  6441. } else {
  6442. if (p.y+1 < term->rows &&
  6443. (ldata->lattr & LATTR_WRAPPED)) {
  6444. termline *ldata2;
  6445. ldata2 = lineptr(p.y+1);
  6446. if (wordtype(term, UCSGET(ldata2->chars, 0))
  6447. == wvalue) {
  6448. p.x = 0;
  6449. p.y++;
  6450. unlineptr(ldata);
  6451. ldata = ldata2;
  6452. } else {
  6453. unlineptr(ldata2);
  6454. break;
  6455. }
  6456. } else
  6457. break;
  6458. }
  6459. }
  6460. } else {
  6461. while (1) {
  6462. if (p.x > 0) {
  6463. if (wordtype(term, UCSGET(ldata->chars, p.x-1)) == wvalue)
  6464. p.x--;
  6465. else
  6466. break;
  6467. } else {
  6468. termline *ldata2;
  6469. int maxcols;
  6470. if (p.y <= topy)
  6471. break;
  6472. ldata2 = lineptr(p.y-1);
  6473. maxcols = line_cols(term, ldata2);
  6474. if (ldata2->lattr & LATTR_WRAPPED) {
  6475. if (wordtype(term, UCSGET(ldata2->chars, maxcols-1))
  6476. == wvalue) {
  6477. p.x = maxcols-1;
  6478. p.y--;
  6479. unlineptr(ldata);
  6480. ldata = ldata2;
  6481. } else {
  6482. unlineptr(ldata2);
  6483. break;
  6484. }
  6485. } else
  6486. break;
  6487. }
  6488. }
  6489. }
  6490. break;
  6491. case SM_LINE:
  6492. /*
  6493. * In this mode, every line is a unit.
  6494. */
  6495. p.x = (dir == -1 ? 0 : term->cols - 1);
  6496. break;
  6497. }
  6498. unlineptr(ldata);
  6499. return p;
  6500. }
  6501. static void sel_spread(Terminal *term)
  6502. {
  6503. if (term->seltype == LEXICOGRAPHIC) {
  6504. term->selstart = sel_spread_half(term, term->selstart, -1);
  6505. decpos(term->selend);
  6506. term->selend = sel_spread_half(term, term->selend, +1);
  6507. incpos(term->selend);
  6508. }
  6509. }
  6510. static void term_paste_callback(void *vterm)
  6511. {
  6512. Terminal *term = (Terminal *)vterm;
  6513. if (term->paste_len == 0)
  6514. return;
  6515. while (term->paste_pos < term->paste_len) {
  6516. int n = 0;
  6517. while (n + term->paste_pos < term->paste_len) {
  6518. if (term->paste_buffer[term->paste_pos + n++] == '\015')
  6519. break;
  6520. }
  6521. if (term->ldisc) {
  6522. strbuf *buf = term_input_data_from_unicode(
  6523. term, term->paste_buffer + term->paste_pos, n);
  6524. term_keyinput_internal(term, buf->s, buf->len, false);
  6525. strbuf_free(buf);
  6526. }
  6527. term->paste_pos += n;
  6528. if (term->paste_pos < term->paste_len) {
  6529. queue_toplevel_callback(term_paste_callback, term);
  6530. return;
  6531. }
  6532. }
  6533. term_bracketed_paste_stop(term);
  6534. sfree(term->paste_buffer);
  6535. term->paste_buffer = NULL;
  6536. term->paste_len = 0;
  6537. }
  6538. /*
  6539. * Specialist string compare function. Returns true if the buffer of
  6540. * alen wide characters starting at a has as a prefix the buffer of
  6541. * blen characters starting at b.
  6542. */
  6543. static bool wstartswith(const wchar_t *a, size_t alen,
  6544. const wchar_t *b, size_t blen)
  6545. {
  6546. return alen >= blen && !wcsncmp(a, b, blen);
  6547. }
  6548. void term_do_paste(Terminal *term, const wchar_t *data, int len)
  6549. {
  6550. const wchar_t *p;
  6551. bool paste_controls = conf_get_bool(term->conf, CONF_paste_controls);
  6552. /*
  6553. * Pasting data into the terminal counts as a keyboard event (for
  6554. * purposes of the 'Reset scrollback on keypress' config option),
  6555. * unless the paste is zero-length.
  6556. */
  6557. if (len == 0)
  6558. return;
  6559. term_seen_key_event(term);
  6560. if (term->paste_buffer)
  6561. sfree(term->paste_buffer);
  6562. term->paste_pos = term->paste_len = 0;
  6563. term->paste_buffer = snewn(len + 12, wchar_t);
  6564. if (term->bracketed_paste && !term->no_bracketed_paste)
  6565. term_bracketed_paste_start(term);
  6566. p = data;
  6567. while (p < data + len) {
  6568. wchar_t wc = *p++;
  6569. if (wc == sel_nl[0] &&
  6570. wstartswith(p-1, data+len-(p-1), sel_nl, sel_nl_sz)) {
  6571. /*
  6572. * This is the (platform-dependent) sequence that the host
  6573. * OS uses to represent newlines in clipboard data.
  6574. * Normalise it to a press of CR.
  6575. */
  6576. p += sel_nl_sz - 1;
  6577. wc = '\015';
  6578. }
  6579. if ((wc & ~(wint_t)0x9F) == 0) {
  6580. /*
  6581. * This is a control code, either in the range 0x00-0x1F
  6582. * or 0x80-0x9F. We reject all of these in pastecontrols
  6583. * mode, except for a small set of permitted ones.
  6584. */
  6585. if (!paste_controls) {
  6586. /* In line with xterm 292, accepted control chars are:
  6587. * CR, LF, tab, backspace. (And DEL, i.e. 0x7F, but
  6588. * that's permitted by virtue of not matching the bit
  6589. * mask that got us into this if statement, so we
  6590. * don't have to permit it here. */
  6591. static const unsigned mask =
  6592. (1<<13) | (1<<10) | (1<<9) | (1<<8);
  6593. if (wc > 15 || !((mask >> wc) & 1))
  6594. continue;
  6595. }
  6596. if (wc == '\033' && term->bracketed_paste &&
  6597. wstartswith(p-1, data+len-(p-1), L"\033[201~", 6)) {
  6598. /*
  6599. * Also, in bracketed-paste mode, reject the ESC
  6600. * character that begins the end-of-paste sequence.
  6601. */
  6602. continue;
  6603. }
  6604. }
  6605. term->paste_buffer[term->paste_len++] = wc;
  6606. }
  6607. /* Assume a small paste will be OK in one go. */
  6608. if (term->paste_len < 256) {
  6609. if (term->ldisc) {
  6610. strbuf *buf = term_input_data_from_unicode(
  6611. term, term->paste_buffer, term->paste_len);
  6612. term_keyinput_internal(term, buf->s, buf->len, false);
  6613. strbuf_free(buf);
  6614. }
  6615. if (term->paste_buffer)
  6616. sfree(term->paste_buffer);
  6617. term_bracketed_paste_stop(term);
  6618. term->paste_buffer = NULL;
  6619. term->paste_pos = term->paste_len = 0;
  6620. }
  6621. queue_toplevel_callback(term_paste_callback, term);
  6622. }
  6623. void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked,
  6624. Mouse_Action a, int x, int y, bool shift, bool ctrl, bool alt)
  6625. {
  6626. pos selpoint;
  6627. termline *ldata;
  6628. bool raw_mouse = (term->xterm_mouse &&
  6629. !term->no_mouse_rep &&
  6630. !(term->mouse_override && shift));
  6631. int default_seltype;
  6632. // Don't do anything if mouse movement events weren't requested;
  6633. // Note: return early to avoid doing all of this code on every mouse move
  6634. // event only to throw it away.
  6635. if (a == MA_MOVE && (!raw_mouse || term->xterm_mouse < 3)) {
  6636. return;
  6637. }
  6638. if (y < 0) {
  6639. y = 0;
  6640. if (a == MA_DRAG && !raw_mouse)
  6641. term_scroll(term, 0, -1);
  6642. }
  6643. if (y >= term->rows) {
  6644. y = term->rows - 1;
  6645. if (a == MA_DRAG && !raw_mouse)
  6646. term_scroll(term, 0, +1);
  6647. }
  6648. if (x < 0) {
  6649. if (y > 0 && !raw_mouse && term->seltype != RECTANGULAR) {
  6650. /*
  6651. * When we're using the mouse for normal raster-based
  6652. * selection, dragging off the left edge of a terminal row
  6653. * is treated the same as the right-hand end of the
  6654. * previous row, in that it's considered to identify a
  6655. * point _before_ the first character on row y.
  6656. *
  6657. * But if the mouse action is going to be used for
  6658. * anything else - rectangular selection, or xterm mouse
  6659. * tracking - then we disable this special treatment.
  6660. */
  6661. x = term->cols - 1;
  6662. y--;
  6663. } else
  6664. x = 0;
  6665. }
  6666. if (x >= term->cols)
  6667. x = term->cols - 1;
  6668. selpoint.y = y + term->disptop;
  6669. ldata = lineptr(selpoint.y);
  6670. if ((ldata->lattr & LATTR_MODE) != LATTR_NORM)
  6671. x /= 2;
  6672. /*
  6673. * Transform x through the bidi algorithm to find the _logical_
  6674. * click point from the physical one.
  6675. */
  6676. if (term_bidi_line(term, ldata, y) != NULL) {
  6677. x = term->post_bidi_cache[y].backward[x];
  6678. }
  6679. selpoint.x = x;
  6680. unlineptr(ldata);
  6681. /*
  6682. * If we're in the middle of a selection operation, we ignore raw
  6683. * mouse mode until it's done (we must have been not in raw mouse
  6684. * mode when it started).
  6685. * This makes use of Shift for selection reliable, and avoids the
  6686. * host seeing mouse releases for which they never saw corresponding
  6687. * presses.
  6688. */
  6689. if (raw_mouse &&
  6690. (term->selstate != ABOUT_TO) && (term->selstate != DRAGGING)) {
  6691. int encstate = 0, r, c;
  6692. bool wheel;
  6693. char *response = NULL;
  6694. if (term->ldisc) {
  6695. switch (braw) {
  6696. case MBT_LEFT:
  6697. encstate = 0x00; /* left button down */
  6698. wheel = false;
  6699. break;
  6700. case MBT_MIDDLE:
  6701. encstate = 0x01;
  6702. wheel = false;
  6703. break;
  6704. case MBT_RIGHT:
  6705. encstate = 0x02;
  6706. wheel = false;
  6707. break;
  6708. case MBT_WHEEL_UP:
  6709. encstate = 0x40;
  6710. wheel = true;
  6711. break;
  6712. case MBT_WHEEL_DOWN:
  6713. encstate = 0x41;
  6714. wheel = true;
  6715. break;
  6716. case MBT_WHEEL_LEFT:
  6717. encstate = 0x42;
  6718. wheel = true;
  6719. break;
  6720. case MBT_WHEEL_RIGHT:
  6721. encstate = 0x43;
  6722. wheel = true;
  6723. break;
  6724. case MBT_NOTHING:
  6725. assert( a == MA_MOVE );
  6726. encstate = 0x03; // release; no buttons pressed
  6727. wheel = false;
  6728. break;
  6729. default:
  6730. return;
  6731. }
  6732. if (wheel) {
  6733. /* For mouse wheel buttons, we only ever expect to see
  6734. * MA_CLICK actions, and we don't try to keep track of
  6735. * the buttons being 'pressed' (since without matching
  6736. * click/release pairs that's pointless). */
  6737. if (a != MA_CLICK)
  6738. return;
  6739. } else switch (a) {
  6740. case MA_DRAG:
  6741. if (term->xterm_mouse == 1)
  6742. return;
  6743. encstate += 0x20; // motion indicator
  6744. break;
  6745. case MA_MOVE: // mouse move without buttons
  6746. assert( braw == MBT_NOTHING && bcooked == MBT_NOTHING );
  6747. if (term->xterm_mouse < 3)
  6748. return;
  6749. if (selpoint.x == term->raw_mouse_reported_x &&
  6750. selpoint.y == term->raw_mouse_reported_y)
  6751. return;
  6752. term->raw_mouse_reported_x = x;
  6753. term->raw_mouse_reported_y = y;
  6754. encstate += 0x20; // motion indicator
  6755. break;
  6756. case MA_RELEASE:
  6757. /* If multiple extensions are enabled, the xterm 1006 is used, so it's okay to check for only that */
  6758. if (!term->xterm_extended_mouse)
  6759. encstate = 0x03;
  6760. term->mouse_is_down = 0;
  6761. break;
  6762. case MA_CLICK:
  6763. if (term->mouse_is_down == braw)
  6764. return;
  6765. term->mouse_is_down = braw;
  6766. break;
  6767. default:
  6768. return;
  6769. }
  6770. if (shift)
  6771. encstate += 0x04;
  6772. if (ctrl)
  6773. encstate += 0x10;
  6774. r = y + 1;
  6775. c = x + 1;
  6776. /* Check the extensions in decreasing order of preference. Encoding the release event above assumes that 1006 comes first. */
  6777. if (term->xterm_extended_mouse) {
  6778. response = dupprintf("\033[<%d;%d;%d%c", encstate, c, r,
  6779. a == MA_RELEASE ? 'm' : 'M');
  6780. } else if (term->urxvt_extended_mouse) {
  6781. response = dupprintf("\033[%d;%d;%dM", encstate + 32, c, r);
  6782. } else if (c <= 223 && r <= 223) {
  6783. response = dupprintf("\033[M%c%c%c", encstate + 32,
  6784. c + 32, r + 32);
  6785. }
  6786. if (response) {
  6787. ldisc_send(term->ldisc, response, strlen(response), false);
  6788. sfree(response);
  6789. }
  6790. }
  6791. return;
  6792. }
  6793. /*
  6794. * Set the selection type (rectangular or normal) at the start
  6795. * of a selection attempt, from the state of Alt.
  6796. */
  6797. if (!alt ^ !term->rect_select)
  6798. default_seltype = RECTANGULAR;
  6799. else
  6800. default_seltype = LEXICOGRAPHIC;
  6801. if (term->selstate == NO_SELECTION) {
  6802. term->seltype = default_seltype;
  6803. }
  6804. if (bcooked == MBT_SELECT && a == MA_CLICK) {
  6805. deselect(term);
  6806. term->selstate = ABOUT_TO;
  6807. term->seltype = default_seltype;
  6808. term->selanchor = selpoint;
  6809. term->selmode = SM_CHAR;
  6810. } else if (bcooked == MBT_SELECT && (a == MA_2CLK || a == MA_3CLK)) {
  6811. deselect(term);
  6812. term->selmode = (a == MA_2CLK ? SM_WORD : SM_LINE);
  6813. term->selstate = DRAGGING;
  6814. term->selstart = term->selanchor = selpoint;
  6815. term->selend = term->selstart;
  6816. incpos(term->selend);
  6817. sel_spread(term);
  6818. } else if ((bcooked == MBT_SELECT && a == MA_DRAG) ||
  6819. (bcooked == MBT_EXTEND && a != MA_RELEASE)) {
  6820. if (a == MA_DRAG &&
  6821. (term->selstate == NO_SELECTION || term->selstate == SELECTED)) {
  6822. /*
  6823. * This can happen if a front end has passed us a MA_DRAG
  6824. * without a prior MA_CLICK. OS X GTK does so, for
  6825. * example, if the initial button press was eaten by the
  6826. * WM when it activated the window in the first place. The
  6827. * nicest thing to do in this situation is to ignore
  6828. * further drags, and wait for the user to click in the
  6829. * window again properly if they want to select.
  6830. */
  6831. return;
  6832. }
  6833. if (term->selstate == ABOUT_TO && poseq(term->selanchor, selpoint))
  6834. return;
  6835. if (bcooked == MBT_EXTEND && a != MA_DRAG &&
  6836. term->selstate == SELECTED) {
  6837. if (term->seltype == LEXICOGRAPHIC) {
  6838. /*
  6839. * For normal selection, we extend by moving
  6840. * whichever end of the current selection is closer
  6841. * to the mouse.
  6842. */
  6843. if (posdiff(selpoint, term->selstart) <
  6844. posdiff(term->selend, term->selstart) / 2) {
  6845. term->selanchor = term->selend;
  6846. decpos(term->selanchor);
  6847. } else {
  6848. term->selanchor = term->selstart;
  6849. }
  6850. } else {
  6851. /*
  6852. * For rectangular selection, we have a choice of
  6853. * _four_ places to put selanchor and selpoint: the
  6854. * four corners of the selection.
  6855. */
  6856. if (2*selpoint.x < term->selstart.x + term->selend.x)
  6857. term->selanchor.x = term->selend.x-1;
  6858. else
  6859. term->selanchor.x = term->selstart.x;
  6860. if (2*selpoint.y < term->selstart.y + term->selend.y)
  6861. term->selanchor.y = term->selend.y;
  6862. else
  6863. term->selanchor.y = term->selstart.y;
  6864. }
  6865. term->selstate = DRAGGING;
  6866. }
  6867. if (term->selstate != ABOUT_TO && term->selstate != DRAGGING)
  6868. term->selanchor = selpoint;
  6869. term->selstate = DRAGGING;
  6870. if (term->seltype == LEXICOGRAPHIC) {
  6871. /*
  6872. * For normal selection, we set (selstart,selend) to
  6873. * (selpoint,selanchor) in some order.
  6874. */
  6875. if (poslt(selpoint, term->selanchor)) {
  6876. term->selstart = selpoint;
  6877. term->selend = term->selanchor;
  6878. incpos(term->selend);
  6879. } else {
  6880. term->selstart = term->selanchor;
  6881. term->selend = selpoint;
  6882. incpos(term->selend);
  6883. }
  6884. } else {
  6885. /*
  6886. * For rectangular selection, we may need to
  6887. * interchange x and y coordinates (if the user has
  6888. * dragged in the -x and +y directions, or vice versa).
  6889. */
  6890. term->selstart.x = min(term->selanchor.x, selpoint.x);
  6891. term->selend.x = 1+max(term->selanchor.x, selpoint.x);
  6892. term->selstart.y = min(term->selanchor.y, selpoint.y);
  6893. term->selend.y = max(term->selanchor.y, selpoint.y);
  6894. }
  6895. sel_spread(term);
  6896. } else if ((bcooked == MBT_SELECT || bcooked == MBT_EXTEND) &&
  6897. a == MA_RELEASE) {
  6898. if (term->selstate == DRAGGING) {
  6899. /*
  6900. * We've completed a selection. We now transfer the
  6901. * data to the clipboard.
  6902. */
  6903. clipme(term, term->selstart, term->selend,
  6904. (term->seltype == RECTANGULAR), false,
  6905. term->mouse_select_clipboards,
  6906. term->n_mouse_select_clipboards);
  6907. term->selstate = SELECTED;
  6908. } else
  6909. term->selstate = NO_SELECTION;
  6910. } else if (bcooked == MBT_PASTE
  6911. && (a == MA_CLICK
  6912. #if MULTICLICK_ONLY_EVENT
  6913. || a == MA_2CLK || a == MA_3CLK
  6914. #endif
  6915. )) {
  6916. term_request_paste(term, term->mouse_paste_clipboard);
  6917. }
  6918. /*
  6919. * Since terminal output is suppressed during drag-selects, we
  6920. * should make sure to write any pending output if one has just
  6921. * finished.
  6922. */
  6923. term_out(term, false);
  6924. term_schedule_update(term);
  6925. }
  6926. void term_cancel_selection_drag(Terminal *term)
  6927. {
  6928. /*
  6929. * In unusual circumstances, a mouse drag might be interrupted by
  6930. * something that steals the rest of the mouse gesture. An example
  6931. * is the GTK popup menu appearing. In that situation, we'll never
  6932. * receive the MA_RELEASE that finishes the DRAGGING state, which
  6933. * means terminal output could be suppressed indefinitely. Call
  6934. * this function from the front end in such situations to restore
  6935. * sensibleness.
  6936. */
  6937. if (term->selstate == DRAGGING)
  6938. term->selstate = NO_SELECTION;
  6939. term_out(term, false);
  6940. term_schedule_update(term);
  6941. }
  6942. static int shift_bitmap(bool shift, bool ctrl, bool alt, bool *consumed_alt)
  6943. {
  6944. int bitmap = (shift ? 1 : 0) + (alt ? 2 : 0) + (ctrl ? 4 : 0);
  6945. if (bitmap)
  6946. bitmap++;
  6947. if (alt && consumed_alt)
  6948. *consumed_alt = true;
  6949. return bitmap;
  6950. }
  6951. int format_arrow_key(char *buf, Terminal *term, int xkey,
  6952. bool shift, bool ctrl, bool alt, bool *consumed_alt)
  6953. {
  6954. char *p = buf;
  6955. if (term->vt52_mode)
  6956. p += sprintf(p, "\x1B%c", xkey);
  6957. else {
  6958. bool app_flg = (term->app_cursor_keys && !term->no_applic_c);
  6959. #if 0
  6960. /*
  6961. * RDB: VT100 & VT102 manuals both state the app cursor
  6962. * keys only work if the app keypad is on.
  6963. *
  6964. * SGT: That may well be true, but xterm disagrees and so
  6965. * does at least one application, so I've #if'ed this out
  6966. * and the behaviour is back to PuTTY's original: app
  6967. * cursor and app keypad are independently switchable
  6968. * modes. If anyone complains about _this_ I'll have to
  6969. * put in a configurable option.
  6970. */
  6971. if (!term->app_keypad_keys)
  6972. app_flg = 0;
  6973. #endif
  6974. int bitmap = 0;
  6975. /* Adjustment based on Shift, Ctrl and/or Alt */
  6976. switch (term->sharrow_type) {
  6977. case SHARROW_APPLICATION:
  6978. if (ctrl)
  6979. app_flg = !app_flg;
  6980. break;
  6981. case SHARROW_BITMAP:
  6982. bitmap = shift_bitmap(shift, ctrl, alt, consumed_alt);
  6983. break;
  6984. }
  6985. if (app_flg)
  6986. p += sprintf(p, "\x1BO%c", xkey);
  6987. else if (bitmap)
  6988. p += sprintf(p, "\x1B[1;%d%c", bitmap, xkey);
  6989. else
  6990. p += sprintf(p, "\x1B[%c", xkey);
  6991. }
  6992. return p - buf;
  6993. }
  6994. int format_function_key(char *buf, Terminal *term, int key_number,
  6995. bool shift, bool ctrl, bool alt, bool *consumed_alt)
  6996. {
  6997. char *p = buf;
  6998. static const int key_number_to_tilde_code[] = {
  6999. -1, /* no such key as F0 */
  7000. 11, 12, 13, 14, 15, /*gap*/ 17, 18, 19, 20, 21, /*gap*/
  7001. 23, 24, 25, 26, /*gap*/ 28, 29, /*gap*/ 31, 32, 33, 34,
  7002. };
  7003. assert(key_number > 0);
  7004. assert(key_number < lenof(key_number_to_tilde_code));
  7005. int index = key_number;
  7006. if (term->funky_type != FUNKY_XTERM_216 && term->funky_type != FUNKY_SCO) {
  7007. if (shift && index <= 10) {
  7008. shift = false;
  7009. index += 10;
  7010. }
  7011. }
  7012. int code = key_number_to_tilde_code[index];
  7013. if (term->funky_type == FUNKY_SCO) {
  7014. /* SCO function keys */
  7015. static const char sco_codes[] =
  7016. "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{";
  7017. index = (key_number >= 1 && key_number <= 12) ? key_number - 1 : 0;
  7018. if (shift) index += 12;
  7019. if (ctrl) index += 24;
  7020. p += sprintf(p, "\x1B[%c", sco_codes[index]);
  7021. } else if ((term->vt52_mode || term->funky_type == FUNKY_VT100P) &&
  7022. code >= 11 && code <= 24) {
  7023. int offt = 0;
  7024. if (code > 15)
  7025. offt++;
  7026. if (code > 21)
  7027. offt++;
  7028. if (term->vt52_mode)
  7029. p += sprintf(p, "\x1B%c", code + 'P' - 11 - offt);
  7030. else
  7031. p += sprintf(p, "\x1BO%c", code + 'P' - 11 - offt);
  7032. } else if (term->funky_type == FUNKY_LINUX && code >= 11 && code <= 15) {
  7033. p += sprintf(p, "\x1B[[%c", code + 'A' - 11);
  7034. } else if ((term->funky_type == FUNKY_XTERM ||
  7035. term->funky_type == FUNKY_XTERM_216) &&
  7036. code >= 11 && code <= 14) {
  7037. if (term->vt52_mode)
  7038. p += sprintf(p, "\x1B%c", code + 'P' - 11);
  7039. else {
  7040. int bitmap = 0;
  7041. if (term->funky_type == FUNKY_XTERM_216)
  7042. bitmap = shift_bitmap(shift, ctrl, alt, consumed_alt);
  7043. if (bitmap)
  7044. p += sprintf(p, "\x1B[1;%d%c", bitmap, code + 'P' - 11);
  7045. else
  7046. p += sprintf(p, "\x1BO%c", code + 'P' - 11);
  7047. }
  7048. } else {
  7049. int bitmap = 0;
  7050. if (term->funky_type == FUNKY_XTERM_216)
  7051. bitmap = shift_bitmap(shift, ctrl, alt, consumed_alt);
  7052. if (bitmap)
  7053. p += sprintf(p, "\x1B[%d;%d~", code, bitmap);
  7054. else
  7055. p += sprintf(p, "\x1B[%d~", code);
  7056. }
  7057. return p - buf;
  7058. }
  7059. int format_small_keypad_key(char *buf, Terminal *term, SmallKeypadKey key,
  7060. bool shift, bool ctrl, bool alt,
  7061. bool *consumed_alt)
  7062. {
  7063. char *p = buf;
  7064. int code;
  7065. switch (key) {
  7066. case SKK_HOME: code = 1; break;
  7067. case SKK_INSERT: code = 2; break;
  7068. case SKK_DELETE: code = 3; break;
  7069. case SKK_END: code = 4; break;
  7070. case SKK_PGUP: code = 5; break;
  7071. case SKK_PGDN: code = 6; break;
  7072. default: unreachable("bad small keypad key enum value");
  7073. }
  7074. /* Reorder edit keys to physical order */
  7075. if (term->funky_type == FUNKY_VT400 && code <= 6)
  7076. code = "\0\2\1\4\5\3\6"[code];
  7077. if (term->vt52_mode && code > 0 && code <= 6) {
  7078. p += sprintf(p, "\x1B%c", " HLMEIG"[code]);
  7079. } else if (term->funky_type == FUNKY_SCO) {
  7080. static const char codes[] = "HL.FIG";
  7081. if (code == 3) {
  7082. *p++ = '\x7F';
  7083. } else {
  7084. p += sprintf(p, "\x1B[%c", codes[code-1]);
  7085. }
  7086. } else if ((code == 1 || code == 4) && term->rxvt_homeend) {
  7087. p += sprintf(p, code == 1 ? "\x1B[H" : "\x1BOw");
  7088. } else {
  7089. if (term->vt52_mode) {
  7090. p += sprintf(p, "\x1B[%d~", code);
  7091. } else {
  7092. int bitmap = 0;
  7093. if (term->funky_type == FUNKY_XTERM_216)
  7094. bitmap = shift_bitmap(shift, ctrl, alt, consumed_alt);
  7095. if (bitmap)
  7096. p += sprintf(p, "\x1B[%d;%d~", code, bitmap);
  7097. else
  7098. p += sprintf(p, "\x1B[%d~", code);
  7099. }
  7100. }
  7101. return p - buf;
  7102. }
  7103. int format_numeric_keypad_key(char *buf, Terminal *term, char key,
  7104. bool shift, bool ctrl)
  7105. {
  7106. char *p = buf;
  7107. bool app_keypad = (term->app_keypad_keys && !term->no_applic_k);
  7108. if (term->nethack_keypad && (key >= '1' && key <= '9')) {
  7109. static const char nh_base[] = "bjnh.lyku";
  7110. char c = nh_base[key - '1'];
  7111. if (ctrl && c != '.')
  7112. c &= 0x1F;
  7113. else if (shift && c != '.')
  7114. c += 'A'-'a';
  7115. *p++ = c;
  7116. } else {
  7117. int xkey = 0;
  7118. if (term->funky_type == FUNKY_VT400 ||
  7119. (term->funky_type <= FUNKY_LINUX && app_keypad)) {
  7120. switch (key) {
  7121. case 'G': xkey = 'P'; break;
  7122. case '/': xkey = 'Q'; break;
  7123. case '*': xkey = 'R'; break;
  7124. case '-': xkey = 'S'; break;
  7125. }
  7126. }
  7127. if (app_keypad) {
  7128. switch (key) {
  7129. case '0': xkey = 'p'; break;
  7130. case '1': xkey = 'q'; break;
  7131. case '2': xkey = 'r'; break;
  7132. case '3': xkey = 's'; break;
  7133. case '4': xkey = 't'; break;
  7134. case '5': xkey = 'u'; break;
  7135. case '6': xkey = 'v'; break;
  7136. case '7': xkey = 'w'; break;
  7137. case '8': xkey = 'x'; break;
  7138. case '9': xkey = 'y'; break;
  7139. case '.': xkey = 'n'; break;
  7140. case '\r': xkey = 'M'; break;
  7141. case '+':
  7142. /*
  7143. * Keypad + is tricky. It covers a space that would
  7144. * be taken up on the VT100 by _two_ keys; so we
  7145. * let Shift select between the two. Worse still,
  7146. * in xterm function key mode we change which two...
  7147. */
  7148. if (term->funky_type == FUNKY_XTERM)
  7149. xkey = shift ? 'l' : 'k';
  7150. else
  7151. xkey = shift ? 'm' : 'l';
  7152. break;
  7153. case '/':
  7154. if (term->funky_type == FUNKY_XTERM)
  7155. xkey = 'o';
  7156. break;
  7157. case '*':
  7158. if (term->funky_type == FUNKY_XTERM)
  7159. xkey = 'j';
  7160. break;
  7161. case '-':
  7162. if (term->funky_type == FUNKY_XTERM)
  7163. xkey = 'm';
  7164. break;
  7165. }
  7166. }
  7167. if (xkey) {
  7168. if (term->vt52_mode) {
  7169. if (xkey >= 'P' && xkey <= 'S')
  7170. p += sprintf(p, "\x1B%c", xkey);
  7171. else
  7172. p += sprintf(p, "\x1B?%c", xkey);
  7173. } else
  7174. p += sprintf(p, "\x1BO%c", xkey);
  7175. }
  7176. }
  7177. return p - buf;
  7178. }
  7179. void term_keyinputw(Terminal *term, const wchar_t *widebuf, int len)
  7180. {
  7181. strbuf *buf = term_input_data_from_unicode(term, widebuf, len);
  7182. if (buf->len)
  7183. term_keyinput_internal(term, buf->s, buf->len, true);
  7184. strbuf_free(buf);
  7185. }
  7186. void term_keyinput(Terminal *term, int codepage, const void *str, int len)
  7187. {
  7188. if (codepage < 0 || codepage == term->ucsdata->line_codepage) {
  7189. /*
  7190. * This text needs no translation, either because it's already
  7191. * in the right character set, or because we got the special
  7192. * codepage value -1 from our caller which means 'this data
  7193. * should be charset-agnostic, just send it raw' (for really
  7194. * simple things like control characters).
  7195. */
  7196. term_keyinput_internal(term, str, len, true);
  7197. } else {
  7198. strbuf *buf = term_input_data_from_charset(term, codepage, str, len);
  7199. if (buf->len)
  7200. term_keyinput_internal(term, buf->s, buf->len, true);
  7201. strbuf_free(buf);
  7202. }
  7203. }
  7204. void term_nopaste(Terminal *term)
  7205. {
  7206. if (term->paste_len == 0)
  7207. return;
  7208. sfree(term->paste_buffer);
  7209. term_bracketed_paste_stop(term);
  7210. term->paste_buffer = NULL;
  7211. term->paste_len = 0;
  7212. }
  7213. static void deselect(Terminal *term)
  7214. {
  7215. term->selstate = NO_SELECTION;
  7216. term->selstart.x = term->selstart.y = term->selend.x = term->selend.y = 0;
  7217. }
  7218. void term_lost_clipboard_ownership(Terminal *term, int clipboard)
  7219. {
  7220. if (!(term->n_mouse_select_clipboards > 1 &&
  7221. clipboard == term->mouse_select_clipboards[1]))
  7222. return;
  7223. deselect(term);
  7224. term_update(term);
  7225. /*
  7226. * Since terminal output is suppressed during drag-selects, we
  7227. * should make sure to write any pending output if one has just
  7228. * finished.
  7229. */
  7230. term_out(term, false);
  7231. }
  7232. static void term_added_data(Terminal *term, bool called_from_term_data)
  7233. {
  7234. if (!term->in_term_out) {
  7235. term->in_term_out = true;
  7236. term_out(term, called_from_term_data);
  7237. term->in_term_out = false;
  7238. }
  7239. }
  7240. size_t term_data(Terminal *term, const void *data, size_t len)
  7241. {
  7242. bufchain_add(&term->inbuf, data, len);
  7243. term_added_data(term, true);
  7244. return bufchain_size(&term->inbuf);
  7245. }
  7246. void term_provide_logctx(Terminal *term, LogContext *logctx)
  7247. {
  7248. term->logctx = logctx;
  7249. }
  7250. void term_set_focus(Terminal *term, bool has_focus)
  7251. {
  7252. term->has_focus = has_focus;
  7253. term_schedule_cblink(term);
  7254. }
  7255. /*
  7256. * Provide "auto" settings for remote tty modes, suitable for an
  7257. * application with a terminal window.
  7258. */
  7259. char *term_get_ttymode(Terminal *term, const char *mode)
  7260. {
  7261. const char *val = NULL;
  7262. if (strcmp(mode, "ERASE") == 0) {
  7263. val = term->bksp_is_delete ? "^?" : "^H";
  7264. } else if (strcmp(mode, "IUTF8") == 0) {
  7265. val = (term->ucsdata->line_codepage == CP_UTF8) ? "yes" : "no";
  7266. }
  7267. /* FIXME: perhaps we should set ONLCR based on lfhascr as well? */
  7268. /* FIXME: or ECHO and friends based on local echo state? */
  7269. return dupstr(val);
  7270. }
  7271. struct term_userpass_state {
  7272. prompts_t *prompts;
  7273. size_t curr_prompt;
  7274. enum TermUserpassPromptState {
  7275. TUS_INITIAL, /* haven't even printed the prompt yet */
  7276. TUS_ACTIVE, /* prompt is currently receiving user input */
  7277. TUS_ABORTED, /* user pressed ^C or ^D to cancel prompt */
  7278. } prompt_state;
  7279. Terminal *term;
  7280. TermLineEditor *le;
  7281. TermLineEditorCallbackReceiver le_rcv;
  7282. };
  7283. static void term_userpass_next_prompt(struct term_userpass_state *s);
  7284. /*
  7285. * Signal that a prompts_t is done. This involves sending a
  7286. * notification to the caller, and also turning off our own callback
  7287. * that listens for more data arriving in the ldisc's input queue.
  7288. */
  7289. static inline SeatPromptResult signal_prompts_t(Terminal *term, prompts_t *p,
  7290. SeatPromptResult spr)
  7291. {
  7292. assert(p->callback && "Asynchronous userpass input requires a callback");
  7293. queue_toplevel_callback(p->callback, p->callback_ctx);
  7294. if (term->ldisc)
  7295. ldisc_provide_userpass_le(term->ldisc, NULL);
  7296. p->spr = spr;
  7297. if (p->data) {
  7298. term_userpass_state_free(p->data);
  7299. p->data = NULL;
  7300. }
  7301. return spr;
  7302. }
  7303. /* Tiny wrapper to make it easier to write lots of little strings */
  7304. static inline void term_write(Terminal *term, ptrlen data)
  7305. {
  7306. term_data(term, data.ptr, data.len);
  7307. }
  7308. static void term_lineedit_to_terminal(
  7309. TermLineEditorCallbackReceiver *rcv, ptrlen data)
  7310. {
  7311. struct term_userpass_state *s = container_of(
  7312. rcv, struct term_userpass_state, le_rcv);
  7313. prompt_t *pr = s->prompts->prompts[s->curr_prompt];
  7314. if (pr->echo)
  7315. term_write(s->term, data);
  7316. }
  7317. static void term_lineedit_to_backend(
  7318. TermLineEditorCallbackReceiver *rcv, ptrlen data)
  7319. {
  7320. struct term_userpass_state *s = container_of(
  7321. rcv, struct term_userpass_state, le_rcv);
  7322. prompt_t *pr = s->prompts->prompts[s->curr_prompt];
  7323. put_datapl(pr->result, data);
  7324. }
  7325. static void term_lineedit_newline(TermLineEditorCallbackReceiver *rcv)
  7326. {
  7327. struct term_userpass_state *s = container_of(
  7328. rcv, struct term_userpass_state, le_rcv);
  7329. prompt_t *pr = s->prompts->prompts[s->curr_prompt];
  7330. if (!pr->echo) {
  7331. /* If echo is disabled, we won't have printed the newline in
  7332. * term_lineedit_to_terminal, so print it now */
  7333. term_write(s->term, PTRLEN_LITERAL("\x0D\x0A"));
  7334. }
  7335. ldisc_provide_userpass_le(s->term->ldisc, NULL);
  7336. s->curr_prompt++;
  7337. s->prompt_state = TUS_INITIAL;
  7338. term_userpass_next_prompt(s);
  7339. }
  7340. static void term_lineedit_special(
  7341. TermLineEditorCallbackReceiver *rcv, SessionSpecialCode code, int arg)
  7342. {
  7343. struct term_userpass_state *s = container_of(
  7344. rcv, struct term_userpass_state, le_rcv);
  7345. switch (code) {
  7346. case SS_IP:
  7347. case SS_EOF:
  7348. ldisc_provide_userpass_le(s->term->ldisc, NULL);
  7349. s->prompt_state = TUS_ABORTED;
  7350. signal_prompts_t(s->term, s->prompts, SPR_USER_ABORT);
  7351. default:
  7352. break;
  7353. }
  7354. }
  7355. static const TermLineEditorCallbackReceiverVtable
  7356. term_userpass_lineedit_receiver_vt = {
  7357. .to_terminal = term_lineedit_to_terminal,
  7358. .to_backend = term_lineedit_to_backend,
  7359. .special = term_lineedit_special,
  7360. .newline = term_lineedit_newline,
  7361. };
  7362. static struct term_userpass_state *term_userpass_state_new(
  7363. Terminal *term, prompts_t *prompts)
  7364. {
  7365. struct term_userpass_state *s = snew(struct term_userpass_state);
  7366. s->prompts = prompts;
  7367. s->curr_prompt = 0;
  7368. s->prompt_state = TUS_INITIAL;
  7369. s->term = term;
  7370. s->le_rcv.vt = &term_userpass_lineedit_receiver_vt;
  7371. s->le = lineedit_new(term, LE_INTERRUPT | LE_EOF_ALWAYS | LE_ESC_ERASES,
  7372. &s->le_rcv);
  7373. assert(!term->userpass_state);
  7374. term->userpass_state = s;
  7375. return s;
  7376. }
  7377. static void term_userpass_state_free(struct term_userpass_state *s)
  7378. {
  7379. assert(s->term->userpass_state == s);
  7380. s->term->userpass_state = NULL;
  7381. lineedit_free(s->le);
  7382. sfree(s);
  7383. }
  7384. static void term_userpass_next_prompt(struct term_userpass_state *s)
  7385. {
  7386. if (s->prompt_state != TUS_INITIAL)
  7387. return;
  7388. if (s->curr_prompt < s->prompts->n_prompts) {
  7389. prompt_t *pr = s->prompts->prompts[s->curr_prompt];
  7390. term_write(s->term, ptrlen_from_asciz(pr->prompt));
  7391. s->prompt_state = TUS_ACTIVE;
  7392. ldisc_provide_userpass_le(s->term->ldisc, s->le);
  7393. } else {
  7394. /* This triggers the callback provided by the userpass client,
  7395. * which will call term_userpass_state to fetch the result
  7396. * we're storing here */
  7397. signal_prompts_t(s->term, s->prompts, SPR_OK);
  7398. }
  7399. }
  7400. static bool terminal_use_utf8 = true;
  7401. bool set_legacy_charset_handling(bool newvalue)
  7402. {
  7403. terminal_use_utf8 = !newvalue;
  7404. return true;
  7405. }
  7406. /*
  7407. * Process some terminal data in the course of username/password
  7408. * input.
  7409. */
  7410. SeatPromptResult term_get_userpass_input(Terminal *term, prompts_t *p)
  7411. {
  7412. if (!term->ldisc) {
  7413. /* Can't handle interactive prompts without an ldisc */
  7414. return signal_prompts_t(term, p, SPR_SW_ABORT(
  7415. "Terminal not prepared for interactive prompts"));
  7416. }
  7417. if (p->spr.kind != SPRK_INCOMPLETE) {
  7418. /* We've already finished these prompts, so return the same
  7419. * result again */
  7420. return p->spr;
  7421. }
  7422. struct term_userpass_state *s = (struct term_userpass_state *)p->data;
  7423. if (!s) {
  7424. /*
  7425. * First call. Set some stuff up.
  7426. */
  7427. p->data = s = term_userpass_state_new(term, p);
  7428. p->spr = SPR_INCOMPLETE;
  7429. term->userpass_utf8_override = p->utf8 && terminal_use_utf8;
  7430. /* We only print the `name' caption if we have to... */
  7431. if (p->name_reqd && p->name) {
  7432. ptrlen plname = ptrlen_from_asciz(p->name);
  7433. term_write(term, plname);
  7434. if (!ptrlen_endswith(plname, PTRLEN_LITERAL("\n"), NULL))
  7435. term_write(term, PTRLEN_LITERAL("\r\n"));
  7436. }
  7437. /* ...but we always print any `instruction'. */
  7438. if (p->instruction) {
  7439. ptrlen plinst = ptrlen_from_asciz(p->instruction);
  7440. term_write(term, plinst);
  7441. if (!ptrlen_endswith(plinst, PTRLEN_LITERAL("\n"), NULL))
  7442. term_write(term, PTRLEN_LITERAL("\r\n"));
  7443. }
  7444. /*
  7445. * Zero all the results, in case we abort half-way through.
  7446. */
  7447. {
  7448. int i;
  7449. for (i = 0; i < (int)p->n_prompts; i++)
  7450. prompt_set_result(p->prompts[i], "");
  7451. }
  7452. /* And print the first prompt. */
  7453. term_userpass_next_prompt(s);
  7454. }
  7455. return SPR_INCOMPLETE;
  7456. }
  7457. void term_notify_minimised(Terminal *term, bool minimised)
  7458. {
  7459. term->minimised = minimised;
  7460. }
  7461. void term_notify_palette_changed(Terminal *term)
  7462. {
  7463. palette_reset(term, true);
  7464. }
  7465. void term_notify_window_pos(Terminal *term, int x, int y)
  7466. {
  7467. term->winpos_x = x;
  7468. term->winpos_y = y;
  7469. }
  7470. void term_notify_window_size_pixels(Terminal *term, int x, int y)
  7471. {
  7472. term->winpixsize_x = x;
  7473. term->winpixsize_y = y;
  7474. }