• 围观大神的代码,提高一下精气神


    前言

    互联网很多大佬都是从写代码起家的,像马化腾、丁磊、雷军、张小龙、张一鸣等人,无不是从一行行代码里敲出的天下。他们那个年代,编程语言基本是C++或汇编,github没有兴起,连sourceforge都还没出现(张一鸣年代除外)。所以要写一个优秀软件,个人天赋和勤奋是主要的。大神们写的代码,既有架构的合理性,又有代码的整洁性,是clean code的代表,值得我们广大程序员学习。

    多隆(蔡景现)

    阿里的扫地僧,淘宝最早的几个程序员,多隆从C++到Java,从glibc/kernel到web开发,无一不精。目前身为阿里合伙人,身价几十亿,是代码致富的典范。目前市面上还能找到他写的tbnet和tbsys两个C++库,代码质量也是高水准的。
    tbnet是淘宝的开源异步网络框架,源码见:http://code.taobao.org/p/tb-common-utils/src/trunk/tbnet/。tbsys是一个系统辅助工具库。

    多隆写的线程池类

    这个线程池代码逻辑并不复杂,用过Java或Python线程池的同学都能很快理解。里面用到的STL的基本数据结构如vector也是大家耳熟能详的,调用了系统的线程库,和lock相关函数,不著一字,尽显上手风范,体现了多隆对C++和底层库的娴熟。

    /*
     * (C) 2007-2010 Taobao Inc.
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 as
     * published by the Free Software Foundation.
     *
     *
     * Version: $Id$
     *
     * Authors:
     *   duolong 
     *
     */
    
    #include "ThreadPool.h"
    #include "Functional.h"
    #include "Exception.h"
    #include "Memory.hpp"
    
    using namespace std;
    namespace tbutil
    {
    ThreadPool::ThreadPool(int size , int sizeMax, int sizeWarn,int listSizeMax,int stackSize) :
        _destroyed(false),
        _listSize( 0 ),
        _procSize( 0 ),
        _listSizeMax( listSizeMax),
        _size(size),
        _sizeMax(sizeMax),
        _sizeWarn(sizeWarn),
        _stackSize(0),
        _running(0),
        _inUse(0),
        _load(1.0),
        _promote(true),
        _waitingNumber(0)
    {
        if ( size < 1 )
             size = 1;
    
        if ( sizeMax < size )
              sizeMax = size;
    
        if ( sizeWarn > sizeMax )
             sizeWarn = sizeMax;
    
        if ( stackSize < 0 )
             stackSize = 16 * 1024 * 1024;
        
        const_cast<int&>(_size) = size;
        const_cast<int&>(_sizeMax) = sizeMax;
        const_cast<int&>(_sizeWarn) = sizeWarn;
        const_cast<size_t&>(_stackSize) = static_cast<size_t>(stackSize);
    
        try
        {
            for(int i = 0 ; i < _size ; ++i)
            {
                ThreadPtr thread = new EventHandlerThread(this);
                thread->start(_stackSize);
                _threads.push_back(thread);
                ++_running;
            }
        }
        catch(const Exception& ex)
        {
            destroy();
            joinWithAllThreads();
        }
    }
    
    ThreadPool::~ThreadPool()
    {
        assert(_destroyed);
        _monitor.lock();
        TBSYS_LOG(DEBUG,"_workItem.size: %d,_listSize: %d,_procSize: %d", _workItems.size(),_listSize,_procSize);
        while( !_workItems.empty() ) 
        {
            ThreadPoolWorkItem* workItem = _workItems.front();
            if ( workItem != NULL )
            {
                workItem->destroy();
                tbsys::gDelete(workItem);
            }       
            _workItems.pop_front();
        }
        _monitor.unlock();
    }
    
    void ThreadPool::destroy()
    {
        this->lock();
        assert(!_destroyed);
        _destroyed = true;
        this->notifyAll();
        this->unlock();
        _monitor.lock();
        _monitor.notifyAll();
        _monitor.unlock();
    }
    
    int ThreadPool::execute(ThreadPoolWorkItem* workItem)
    {
        if ( _destroyed)
        {
            //TBSYS_LOG(ERROR,"%s","ThreadPoolDestroyedException");
            return -1;
        }
        if (_listSize > _listSizeMax )
        {
            //TBSYS_LOG(DEBUG,"%s","ThreadPoolQueueFullException");
            return -1;
        }
    
        _monitor.lock();
        _workItems.push_back(workItem);
        ++_listSize;
        _monitor.notify();
        _monitor.unlock();
        return 0;
    }
    
    void ThreadPool::promoteFollower( pthread_t thid )
    {
        if(_sizeMax > 1)
        {
            this->lock();
            assert(!_promote);
            _promote = true;
            this->notify();
    
            if(!_destroyed)
            {
                assert(_inUse >= 0);
                ++_inUse;
                
                if(_inUse == _sizeWarn)
                {
                    /*cout << "thread pool `" << "' is running low on threads\n"
                        << "Size=" << _size << ", " << "SizeMax=" << _sizeMax << ", " 
    		    << "SizeWarn=" << _sizeWarn<<", " <<"_inUse=" <<_inUse << ", "
    		    << "_running=" << _running <<". " <<"threads.size="<< _threads.size() << ", " 
    		    << "_workItems.size="<< _workItems.size()<
                }
                
                assert(_inUse <= _running);
                if(_inUse < _sizeMax && _inUse == _running)
                {
                    try
                    {
                        ThreadPtr thread = new EventHandlerThread(this);
                        thread->start(_stackSize);
                        _threads.push_back(thread);
                        ++_running;
                    }
                    catch(const Exception& ex)
                    {
    		     throw ThreadCreateException(__FILE__,__LINE__);
                    }
                }
            }
            this->unlock();
        }
    }
    
    void ThreadPool::joinWithAllThreads()
    {
        assert(_destroyed);
        for(vector<ThreadPtr>::iterator p = _threads.begin(); p != _threads.end(); ++p)
        {
            (*p)->join();
        }
    }
    
    
    bool ThreadPool::isMaxCapacity() const
    {
        return _listSize > _listSizeMax ? true:false;
    }
    
    bool ThreadPool::run( pthread_t thid)
    {
        ThreadPool* self = this;
        while(true)
        {
            #ifdef DEBUG
            cout<<"["<<thid<<"]debug-1: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
            #endif
            if( _sizeMax > 1 )
    	{
                this->lock();
    	    while( !_promote )
    	    {
                    #ifdef DEBUG
                    cout<<"["<<thid<<"]debug-2: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
                    #endif
                    const bool bRet = this->wait();
                    #ifdef DEBUG
                    cout<<"["<<thid<<"]debug-3: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
                    #endif
                    if ( !bRet )
                    {
                        --_inUse;
                        --_running;
                        this->unlock();
                        return false;
                    }
                    #ifdef DEBUG
                    cout<<"["<<thid<<"]debug-4: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
                    #endif
    	    }
    	    _promote = false;
                this->unlock();
    	}
    
            #ifdef DEBUG
            cout<<"["<<thid<<"]debug-5: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
            #endif
            _monitor.lock();
    	while( (_workItems.empty() && !_destroyed) )
    	{
                #ifdef DEBUG
                cout<<"["<<thid<<"]debug-6: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
                #endif
    	    const bool bRet = _monitor.wait();
                #ifdef DEBUG
                cout<<"["<<thid<<"]debug-7: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
                #endif
                if ( !bRet )
                {
                    --_inUse;
                    --_running;
                    _monitor.unlock();
                    return false;
                }
                #ifdef DEBUG
                cout<<"["<<thid<<"]debug-8: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
                #endif
    	}
    
            #ifdef DEBUG
            cout<<"["<<thid<<"]debug-9: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
            #endif
            if ( _destroyed && _workItems.empty()) 
            {
                _monitor.unlock();
                return true;
            }
    
            ThreadPoolWorkItem* workItem = NULL;
            workItem = _workItems.front();
            _workItems.pop_front();
            ++_procSize;
            --_listSize;
            _monitor.unlock();
    
            #ifdef DEBUG
            cout<<"["<<thid<<"]debug-10: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
            #endif
            promoteFollower(thid);
            #ifdef DEBUG
            cout<<"["<<thid<<"]debug-11: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
            #endif
            if( workItem != NULL && !_destroyed )
            {
                try
                {
                    workItem->execute(self);
                }
                catch(const Exception& ex)
                {
    	        cout << "exception in" << "while calling execute():"<<ex.what()<<endl;
                }
                tbsys::gDelete( workItem );
            }
            else
            {
                if ( workItem != NULL )
                {
                    workItem->destroy();
                    tbsys::gDelete( workItem );
                }
            }
            #ifdef DEBUG
            cout<<"["<<thid<<"]debug-12: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
            #endif
            if(_sizeMax > 1)
            {
                this->lock();
                if(!_destroyed)
                {
                    const int sz = static_cast<int>(_threads.size());
                    assert(_running <= sz);
                    if(_running < sz)
                    {
                        vector<ThreadPtr>::iterator start =
                           partition(_threads.begin(), _threads.end(), constMemFun(&Thread::isAlive));
    
                        for(vector<ThreadPtr>::iterator p = start; p != _threads.end(); ++p)
                        {
                            (*p)->join();
                            --_running;
                        }
    
                        _threads.erase(start, _threads.end());
                    }
                    #ifdef DEBUG
                    cout<<"["<<thid<<"]debug-13: size:"<<_workItems.size()<<",_promote: "<<_promote<<endl ;
                    #endif
                    /*double inUse = static_cast(_inUse);
                    if(_load < inUse)
                    {
                        _load = inUse;
                    }
                    else
                    {
                        const double loadFactor = 0.05; // TODO: Configurable?
                        const double oneMinusLoadFactor = 1 - loadFactor;
                        _load = _load * oneMinusLoadFactor + inUse * loadFactor;
                    }
                    
                    if(_running > _size)
                    {
                        cout<<"_running: "<<_running<<"_size :"<<_size<(_load + 0.5);
                        if(load + 1 < _running)
                        {
                            assert(_inUse > 0);
                            --_inUse;
                            
                            assert(_running > 0);
                            --_running;
                            this->unlock();    
                            return false;
                        }
                    }*/
                    assert(_inUse > 0);
                    --_inUse;
                }
                this->unlock();
            }//end _sizeMax > 1
        }//end while
    }
    
    ThreadPool::EventHandlerThread::EventHandlerThread(const ThreadPool* pool) 
    {
        _pool = (ThreadPool*)pool;
    }
    
    void ThreadPool::EventHandlerThread::run()
    {
        bool promote;
    
        try
        {
            promote = _pool->run( id() );
        }
        catch(const std::exception& ex)
        {
            promote = true;
    	cout<<ex.what() <<endl;
        }
        catch(...)
        {
            cout << "unknown exception in ThreadPool::EventHandlerThread::run() "<<endl; 
            promote = true;
        }
    
        #ifdef DEBUG
        cout<<"["<<id()<<"]debug-14:_promote: "<<_pool->_promote<<endl ;
        #endif
        if( promote && _pool->_sizeMax > 1)
        {
            {
                _pool->lock();
                assert(!_pool->_promote);
                _pool->_promote = true;
                _pool->notify();
                _pool->unlock();
            }
        }
    }
    }//end namespace tbutil
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384

    云风

    网易的游戏编程大家,大话西游的主打程序员,《我的游戏编程感悟》作者。编程感悟一书和梁肇新的《编程高手箴言》都是windows编程里的优秀书籍。云风属性C语言编程,对图形学和图像编程有深厚的造诣。当年,丁磊亲自飞到武汉聘请云风出山。后来,云风离开网易,合伙创办了简悦 (EJOY)游戏公司。最早云风写的风魂和风魂++2D游戏引擎,在网易多款游戏中大放光芒。后来,云风推出了Ejoy2D,适用移动版,是一款图形引擎、基于C和Lua开发,底层是一个十分简单的核心层,基本上只负担绘制工作,上层语言是Lua。Ejoy2D旨在帮助开发人员轻松地嵌入到游戏引擎中,方便开发者定制自己所需的功能。此外,还有开源的游戏服务器框架Skynet值得一读。
    代码在:https://github.com/ejoy/ejoy2d.git
    Ejoy2D其实是对OpenGL ES的一个浅封装。云风并没有打算把它发展成一个2D游戏引擎,而只停留在图形引擎层面上。但和别的引擎相比较大的区别是,它天生为和Lua结合而设计并实现的。

    ejoy2d中游戏精灵的实现:

    #include "sprite.h"
    #include "spritepack.h"
    #include "shader.h"
    #include "texture.h"
    #include "screen.h"
    #include "matrix.h"
    #include "label.h"
    #include "scissor.h"
    #include "array.h"
    #include "particle.h"
    #include "material.h"
    
    #include 
    #include 
    #include 
    #include 
    
    void
    sprite_drawquad(struct pack_picture *picture, const struct srt *srt,  const struct sprite_trans *arg) {
    	struct matrix tmp;
    	struct vertex_pack vb[4];
    	int i,j;
    	if (arg->mat == NULL) {
    		matrix_identity(&tmp);
    	} else {
    		tmp = *arg->mat;
    	}
    	matrix_srt(&tmp, srt);
    	int *m = tmp.m;
    	for (i=0;i<picture->n;i++) {
    		struct pack_quad *q = &picture->rect[i];
    		int glid = texture_glid(q->texid);
    		if (glid == 0)
    			continue;
    		shader_texture(glid, 0);
    		for (j=0;j<4;j++) {
    			int xx = q->screen_coord[j*2+0];
    			int yy = q->screen_coord[j*2+1];
    			float vx = (xx * m[0] + yy * m[2]) / 1024 + m[4];
    			float vy = (xx * m[1] + yy * m[3]) / 1024 + m[5];
    			float tx = q->texture_coord[j*2+0];
    			float ty = q->texture_coord[j*2+1];
    
    			screen_trans(&vx,&vy);
    			vb[j].vx = vx;
    			vb[j].vy = vy;
    			vb[j].tx = tx;
    			vb[j].ty = ty;
    		}
    		shader_draw(vb, arg->color, arg->additive);
    	}
    }
    
    void
    sprite_drawpolygon(struct sprite_pack *pack, struct pack_polygon_data *poly, const struct srt *srt, const struct sprite_trans *arg) {
    	struct matrix tmp;
    	int i,j;
    	if (arg->mat == NULL) {
    		matrix_identity(&tmp);
    	} else {
    		tmp = *arg->mat;
    	}
    	matrix_srt(&tmp, srt);
    	int *m = tmp.m;
    	for (i=0;i<poly->n;i++) {
    		struct pack_poly_data *p = &poly->poly[i];
    		int glid = texture_glid(p->texid);
    		if (glid == 0)
    			continue;
    		shader_texture(glid, 0);
    		int pn = p->n;
    
    		ARRAY(struct vertex_pack, vb, pn);
    
    		uv_t * texture_coord = OFFSET_TO_POINTER(uv_t, pack, p->texture_coord);
    		int32_t * screen_coord = OFFSET_TO_POINTER(int32_t, pack, p->screen_coord);
    
    		for (j=0;j<pn;j++) {
    			int xx = screen_coord[j*2+0];
    			int yy = screen_coord[j*2+1];
    
    
    			float vx = (xx * m[0] + yy * m[2]) / 1024 + m[4];
    			float vy = (xx * m[1] + yy * m[3]) / 1024 + m[5];
    			float tx = texture_coord[j*2+0];
    			float ty = texture_coord[j*2+1];
    
    			screen_trans(&vx,&vy);
    
    			vb[j].vx = vx;
    			vb[j].vy = vy;
    			vb[j].tx = tx;
    			vb[j].ty = ty;
    		}
    		shader_drawpolygon(pn, vb, arg->color, arg->additive);
    	}
    }
    
    int
    sprite_size(struct sprite_pack *pack, int id) {
    	if (id < 0 || id >=	pack->n)
    		return 0;
    	int8_t * type_array = OFFSET_TO_POINTER(int8_t, pack, pack->type);
    	int type = type_array[id];
    	if (type == TYPE_ANIMATION) {
    		offset_t *data = OFFSET_TO_POINTER(offset_t, pack, pack->data);
    		struct pack_animation * ani = OFFSET_TO_POINTER(struct pack_animation, pack, data[id]);
    		return sizeof(struct sprite) + (ani->component_number - 1) * sizeof(struct sprite *);
    	} else {
    		return sizeof(struct sprite);
    	}
    	return 0;
    }
    
    int
    sprite_action(struct sprite *s, const char * action) {
    	if (s->type != TYPE_ANIMATION) {
    		return -1;
    	}
    	struct pack_animation *ani = s->s.ani;
    	struct pack_action *pa = OFFSET_TO_POINTER(struct pack_action, s->pack, ani->action);
    	if (action == NULL) {
    		if (ani->action == 0) {
    			return -1;
    		}
    		s->start_frame = pa[0].start_frame;
    		s->total_frame = pa[0].number;
    		s->frame = 0;
    		return s->total_frame;
    	} else {
    		int i;
    		for (i=0;i<ani->action_number;i++) {
    			const char *name = OFFSET_TO_STRING(s->pack, pa[i].name);
    			if (name) {
    				if (strcmp(name, action)==0) {
    					s->start_frame = pa[i].start_frame;
    					s->total_frame = pa[i].number;
    					s->frame = 0;
    					return s->total_frame;
    				}
    			}
    		}
    		return -1;
    	}
    }
    
    void
    sprite_init(struct sprite * s, struct sprite_pack * pack, int id, int sz) {
    	if (id < 0 || id >=	pack->n)
    		return;
    	s->parent = NULL;
    	s->pack = pack;
    	s->t.mat = NULL;
    	s->t.color = 0xffffffff;
    	s->t.additive = 0;
    	s->t.program = PROGRAM_DEFAULT;
    	s->flags = 0;
    	s->name = NULL;
    	s->id = id;
    	uint8_t *type_array = OFFSET_TO_POINTER(uint8_t, pack, pack->type);
    	s->type = type_array[id];
    	s->material = NULL;
    	offset_t *data = OFFSET_TO_POINTER(offset_t, pack, pack->data);
    	if (s->type == TYPE_ANIMATION) {
    		struct pack_animation * ani = OFFSET_TO_POINTER(struct pack_animation, pack, data[id]);
    		s->s.ani = ani;
    		s->frame = 0;
    		s->start_frame = 0;
    		s->total_frame = 0;
    		sprite_action(s, NULL);
    		int i;
    		int n = ani->component_number;
    		assert(sz >= sizeof(struct sprite) + (n - 1) * sizeof(struct sprite *));
    		for (i=0; i<n ;i++) {
    			s->data.children[i] = NULL;
    		}
    	} else {
    		// may be polygon depend on  s->type
    		s->s.pic = OFFSET_TO_POINTER(struct pack_picture, pack, data[id]);
    		s->start_frame = 0;
    		s->total_frame = 0;
    		s->frame = 0;
    		memset(&s->data, 0, sizeof(s->data));
    		assert(sz >= sizeof(struct sprite) - sizeof(struct sprite *));
    		if (s->type == TYPE_PANNEL) {
    			struct pack_pannel * pp = OFFSET_TO_POINTER(struct pack_pannel, pack, data[id]);
    			s->data.scissor = pp->scissor;
    		}
    	}
    }
    
    void
    sprite_mount(struct sprite *parent, int index, struct sprite *child) {
    	assert(parent->type == TYPE_ANIMATION);
    	struct pack_animation *ani = parent->s.ani;
    	assert(index >= 0 && index < ani->component_number);
    	struct sprite * oldc = parent->data.children[index];
    	if (oldc) {
    		oldc->parent = NULL;
    		oldc->name = NULL;
    	}
    	parent->data.children[index] = child;
    	if (child) {
    		assert(child->parent == NULL);
    		if ((child->flags & SPRFLAG_MULTIMOUNT) == 0) {
    			child->name = OFFSET_TO_STRING(parent->pack, ani->component[index].name);
    			child->parent = parent;
    		}
    		if (oldc && oldc->type == TYPE_ANCHOR) {
    			if(oldc->flags & SPRFLAG_MESSAGE) {
    				child->flags |= SPRFLAG_MESSAGE;
    			} else {
    				child->flags &= ~SPRFLAG_MESSAGE;
    			}
    		}
    	}
    }
    
    static inline int
    get_frame(struct sprite *s) {
    	if (s->type != TYPE_ANIMATION) {
    		return s->start_frame;
    	}
    	if (s->total_frame <= 0) {
    		return -1;
    	}
    	int f = s->frame % s->total_frame;
    	if (f < 0) {
    		f += s->total_frame;
    	}
    	return f + s->start_frame;
    }
    
    int
    sprite_child(struct sprite *s, const char * childname) {
    	assert(childname);
    	if (s->type != TYPE_ANIMATION)
    		return -1;
    	struct pack_animation *ani = s->s.ani;
    	int i;
    	for (i=0;i<ani->component_number;i++) {
    		const char *name = OFFSET_TO_STRING(s->pack, ani->component[i].name);
    		if (name) {
    			if (strcmp(name, childname)==0) {
    				return i;
    			}
    		}
    	}
    	return -1;
    }
    
    int
    sprite_child_ptr(struct sprite *s, struct sprite *child) {
    	if (s->type != TYPE_ANIMATION)
    		return -1;
    	struct pack_animation *ani = s->s.ani;
    	int i;
    	for (i=0;i<ani->component_number;i++) {
    		struct sprite * c = s->data.children[i];
    		if (c == child)
    			return i;
    	}
    	return -1;
    }
    
    int
    sprite_component(struct sprite *s, int index) {
    	if (s->type != TYPE_ANIMATION)
    		return -1;
    	struct pack_animation *ani = s->s.ani;
    	if (index < 0 || index >= ani->component_number)
    		return -1;
    	return ani->component[index].id;
    }
    
    const char *
    sprite_childname(struct sprite *s, int index) {
    	if (s->type != TYPE_ANIMATION)
    		return NULL;
    	struct pack_animation *ani = s->s.ani;
    	if (index < 0 || index >= ani->component_number)
    		return NULL;
    	return OFFSET_TO_STRING(s->pack, ani->component[index].name);
    }
    
    // draw sprite
    
    static inline uint32_t
    color_mul(uint32_t c1, uint32_t c2) {
    	int r1 = (c1 >> 24) & 0xff;
    	int g1 = (c1 >> 16) & 0xff;
    	int b1 = (c1 >> 8) & 0xff;
    	int a1 = (c1) & 0xff;
    	int r2 = (c2 >> 24) & 0xff;
    	int g2 = (c2 >> 16) & 0xff;
    	int b2 = (c2 >> 8) & 0xff;
    	int a2 = c2 & 0xff;
    
    	return (r1 * r2 /255) << 24 |
    		(g1 * g2 /255) << 16 |
    		(b1 * b2 /255) << 8 |
    		(a1 * a2 /255) ;
    }
    
    static inline unsigned int
    clamp(unsigned int c) {
    	return ((c) > 255 ? 255 : (c));
    }
    
    static inline uint32_t
    color_add(uint32_t c1, uint32_t c2) {
    	int r1 = (c1 >> 16) & 0xff;
    	int g1 = (c1 >> 8) & 0xff;
    	int b1 = (c1) & 0xff;
    	int r2 = (c2 >> 16) & 0xff;
    	int g2 = (c2 >> 8) & 0xff;
    	int b2 = (c2) & 0xff;
    	return clamp(r1+r2) << 16 |
    		clamp(g1+g2) << 8 |
    		clamp(b1+b2);
    }
    
    static inline void
    sprite_trans_mul_(struct sprite_trans *b, struct sprite_trans *t, struct matrix *tmp_matrix) {
    	if (t->mat == NULL) {
    		t->mat = b->mat;
    	} else if (b->mat) {
    		matrix_mul(tmp_matrix, t->mat, b->mat);
    		t->mat = tmp_matrix;
    	}
    	if (t->color == 0xffffffff) {
    		t->color = b->color;
    	} else if (b->color != 0xffffffff) {
    		t->color = color_mul(t->color, b->color);
    	}
    	if (t->additive == 0) {
    		t->additive = b->additive;
    	} else if (b->additive != 0) {
    		t->additive = color_add(t->additive, b->additive);
    	}
    }
    
    struct sprite_trans *
    sprite_trans_mul2(struct sprite_pack *pack, struct sprite_trans_data *a, struct sprite_trans *b, struct sprite_trans *t, struct matrix *tmp_matrix) {
    	if (b == NULL && a == NULL) {
    		return NULL;
    	}
    	t->mat = OFFSET_TO_POINTER(struct matrix, pack, a->mat);
    	t->color = a->color;
    	t->additive = a->additive;
    	t->program = PROGRAM_DEFAULT;
    	sprite_trans_mul_(b , t, tmp_matrix);
    	t->program = b->program;
    
    	return t;
    }
    
    struct sprite_trans *
    sprite_trans_mul(struct sprite_trans *a, struct sprite_trans *b, struct sprite_trans *t, struct matrix *tmp_matrix) {
    	if (b == NULL) {
    		return a;
    	}
    	*t = *a;
    	sprite_trans_mul_(b , t, tmp_matrix);
    	if (t->program == PROGRAM_DEFAULT) {
    		t->program = b->program;
    	}
    	return t;
    }
    
    static struct matrix *
    mat_mul(struct matrix *a, struct matrix *b, struct matrix *tmp) {
    	if (b == NULL)
    		return a;
    	if (a == NULL)
    		return b;
    	matrix_mul(tmp, a , b);
    	return tmp;
    }
    
    static void
    switch_program(struct sprite_trans *t, int def, struct material *m) {
    	int prog = t->program;
    	if (prog == PROGRAM_DEFAULT) {
    		prog = def;
    	}
    	shader_program(prog, m);
    }
    
    static void
    set_scissor(const struct pack_pannel *p, const struct srt *srt, const struct sprite_trans *arg) {
    	struct matrix tmp;
    	if (arg->mat == NULL) {
    		matrix_identity(&tmp);
    	} else {
    		tmp = *arg->mat;
    	}
    	matrix_srt(&tmp, srt);
    	int *m = tmp.m;
    	int x[4] = { 0, p->width * SCREEN_SCALE, p->width * SCREEN_SCALE, 0 };
    	int y[4] = { 0, 0, p->height * SCREEN_SCALE, p->height * SCREEN_SCALE };
    	int minx = (x[0] * m[0] + y[0] * m[2]) / 1024 + m[4];
    	int miny = (x[0] * m[1] + y[0] * m[3]) / 1024 + m[5];
    	int maxx = minx;
    	int maxy = miny;
    	int i;
    	for (i=1;i<4;i++) {
    		int vx = (x[i] * m[0] + y[i] * m[2]) / 1024 + m[4];
    		int vy = (x[i] * m[1] + y[i] * m[3]) / 1024 + m[5];
    		if (vx<minx) {
    			minx = vx;
    		} else if (vx > maxx) {
    			maxx = vx;
    		}
    		if (vy<miny) {
    			miny = vy;
    		} else if (vy > maxy) {
    			maxy = vy;
    		}
    	}
    	minx /= SCREEN_SCALE;
    	miny /= SCREEN_SCALE;
    	maxx /= SCREEN_SCALE;
    	maxy /= SCREEN_SCALE;
    	scissor_push(minx,miny,maxx-minx,maxy-miny);
    }
    
    static void
    anchor_update(struct sprite *s, struct srt *srt, struct sprite_trans *arg) {
    	struct matrix *r = s->s.mat;
    	if (arg->mat == NULL) {
    		matrix_identity(r);
    	} else {
    		*r = *arg->mat;
    	}
    	matrix_srt(r, srt);
    }
    
    static void
    label_pos(int m[6], struct pack_label * l, int pos[2]) {
    	float c_x = l->width * SCREEN_SCALE / 2.0;
    	float c_y = l->height * SCREEN_SCALE / 2.0;
    	pos[0] = (int)((c_x * m[0] + c_y * m[2]) / 1024 + m[4])/SCREEN_SCALE;
    	pos[1] = (int)((c_x * m[1] + c_y * m[3]) / 1024 + m[5])/SCREEN_SCALE;
    }
    
    static void
    picture_pos(int m[6], struct pack_picture *picture, int pos[2]) {
    	int max_x = INT_MIN;
    	int max_y = -INT_MAX;
    	int min_x = INT_MAX;
    	int min_y = INT_MAX;
    	int i,j;
    	for (i=0;i<picture->n;i++) {
    		struct pack_quad *q = &picture->rect[i];
    		for (j=0;j<4;j++) {
    			int xx = q->screen_coord[j*2+0];
    			int yy = q->screen_coord[j*2+1];
    
    			if (xx > max_x) max_x = xx;
    			if (yy > max_y) max_y = yy;
    			if (xx < min_x) min_x = xx;
    			if (yy < min_y) min_y = yy;
    		}
    	}
    
    	float c_x = (max_x + min_x) / 2.0;
    	float c_y = (max_y + min_y) / 2.0;
    	pos[0] = (int)((c_x * m[0] + c_y * m[2]) / 1024 + m[4])/SCREEN_SCALE;
    	pos[1] = (int)((c_x * m[1] + c_y * m[3]) / 1024 + m[5])/SCREEN_SCALE;
    }
    
    static void
    drawparticle(struct sprite *s, struct particle_system *ps, struct pack_picture *pic, const struct srt *srt) {
    	int n = ps->particleCount;
    	int i;
    	struct matrix *old_m = s->t.mat;
    	uint32_t old_c = s->t.color;
    
    	shader_blend(ps->config->srcBlend, ps->config->dstBlend);
    	for (i=0;i<n;i++) {
    		struct particle *p = &ps->particles[i];
    		struct matrix *mat = &ps->matrix[i];
    		uint32_t color = p->color_val;
    
    		s->t.mat = mat;
    		s->t.color = color;
    		sprite_drawquad(pic, NULL, &s->t);
    	}
    	shader_defaultblend();
    
    	s->t.mat = old_m;
    	s->t.color = old_c;
    }
    
    static int
    draw_child(struct sprite *s, struct srt *srt, struct sprite_trans * ts, struct material * material) {
    	struct sprite_trans temp;
    	struct matrix temp_matrix;
    	struct sprite_trans *t = sprite_trans_mul(&s->t, ts, &temp, &temp_matrix);
    	if (s->material) {
    		material = s->material;
    	} 
    	switch (s->type) {
    	case TYPE_PICTURE:
    		switch_program(t, PROGRAM_PICTURE, material);
    		sprite_drawquad(s->s.pic, srt, t);
    		return 0;
    	case TYPE_POLYGON:
    		switch_program(t, PROGRAM_PICTURE, material);
    		sprite_drawpolygon(s->pack, s->s.poly, srt, t);
    		return 0;
    	case TYPE_LABEL:
    		if (s->data.rich_text) {
    			t->program = PROGRAM_DEFAULT;	// label never set user defined program
    			switch_program(t, s->s.label->edge ? PROGRAM_TEXT_EDGE : PROGRAM_TEXT, material);
    			label_draw(s->data.rich_text, s->s.label, srt, t);
    		}
    		return 0;
    	case TYPE_ANCHOR:
    		if (s->data.anchor->ps){
    			switch_program(t, PROGRAM_PICTURE, material);
    			drawparticle(s, s->data.anchor->ps, s->data.anchor->pic, srt);
    		}
    		anchor_update(s, srt, t);
    		return 0;
    	case TYPE_ANIMATION:
    		break;
    	case TYPE_PANNEL:
    		if (s->data.scissor) {
    			// enable scissor
    			set_scissor(s->s.pannel, srt, t);
    			return 1;
    		} else {
    			return 0;
    		}
    	default:
    		// todo : invalid type
    		return 0;
    	}
    	// draw animation
    	int frame = get_frame(s);
    	if (frame < 0) {
    		return 0;
    	}
    	struct pack_animation *ani = s->s.ani;
    	struct pack_frame * pf = OFFSET_TO_POINTER(struct pack_frame, s->pack, ani->frame);
    	pf = &pf[frame];
    	int i;
    	int scissor = 0;
    	for (i=0;i<pf->n;i++) {
    		struct pack_part *pp = OFFSET_TO_POINTER(struct pack_part, s->pack, pf->part);
    		pp = &pp[i];
    		int index = pp->component_id;
    		struct sprite * child = s->data.children[index];
    		if (child == NULL || (child->flags & SPRFLAG_INVISIBLE)) {
    			continue;
    		}
    		struct sprite_trans temp2;
    		struct matrix temp_matrix2;
    		struct sprite_trans *ct = sprite_trans_mul2(s->pack, &pp->t, t, &temp2, &temp_matrix2);
    		scissor += draw_child(child, srt, ct, material);
    	}
    	for (i=0;i<scissor;i++) {
    		scissor_pop();
    	}
    	return 0;
    }
    
    bool
    sprite_child_visible(struct sprite *s, const char * childname) {
    	struct pack_animation *ani = s->s.ani;
    	int frame = get_frame(s);
    	if (frame < 0) {
    		return false;
    	}
    	struct pack_frame * pf = OFFSET_TO_POINTER(struct pack_frame, s->pack, ani->frame);
    	pf = &pf[frame];
    	int i;
    	for (i=0;i<pf->n;i++) {
    		struct pack_part *pp = OFFSET_TO_POINTER(struct pack_part, s->pack, pf->part);
    		pp = &pp[i];
    		int index = pp->component_id;
    		struct sprite * child = s->data.children[index];
    		if (child->name && strcmp(childname, child->name) == 0) {
    			return true;
    		}
    	}
    	return false;
    }
    
    void
    sprite_draw(struct sprite *s, struct srt *srt) {
    	if ((s->flags & SPRFLAG_INVISIBLE) == 0) {
    		draw_child(s, srt, NULL, NULL);
    	}
    }
    
    void
    sprite_draw_as_child(struct sprite *s, struct srt *srt, struct matrix *mat, uint32_t color) {
    	if ((s->flags & SPRFLAG_INVISIBLE) == 0) {
    		struct sprite_trans st;
    		st.mat = mat;
    		st.color = color;
    		st.additive = 0;
    		st.program = PROGRAM_DEFAULT;
    		draw_child(s, srt, &st, NULL);
    	}
    }
    
    int
    sprite_pos(struct sprite *s, struct srt *srt, struct matrix *m, int pos[2]) {
    	struct matrix temp;
    	struct matrix *t = mat_mul(s->t.mat, m, &temp);
    	matrix_srt(t, srt);
    	switch (s->type) {
    	case TYPE_PICTURE:
    		picture_pos(t->m, s->s.pic, pos);
    		return 0;
    	case TYPE_LABEL:
    		label_pos(t->m, s->s.label, pos);
    		return 0;
    	case TYPE_ANIMATION:
    	case TYPE_PANNEL:
    		pos[0] = t->m[4] / SCREEN_SCALE;
    		pos[1] = t->m[5] / SCREEN_SCALE;
    		return 0;
    	default:
    		return 1;
    	}
    
    }
    
    void
    sprite_matrix(struct sprite * self, struct matrix *mat) {
    	struct sprite * parent = self->parent;
    	if (parent) {
    		assert(parent->type == TYPE_ANIMATION);
    		sprite_matrix(parent, mat);
    		struct matrix tmp;
    		struct matrix * parent_mat = parent->t.mat;
    
    		struct matrix * child_mat = NULL;
    		struct pack_animation *ani = parent->s.ani;
    		int frame = get_frame(parent);
    		if (frame < 0) {
    			return;
    		}
    		struct pack_frame * pf = OFFSET_TO_POINTER(struct pack_frame, parent->pack, ani->frame);
    		pf = &pf[frame];
    		int i;
    		for (i=0;i<pf->n;i++) {
    			struct pack_part *pp = OFFSET_TO_POINTER(struct pack_part, parent->pack, pf->part);
    			pp = &pp[i];
    			int index = pp->component_id;
    			struct sprite * child = parent->data.children[index];
    			if (child == self) {
    				child_mat = OFFSET_TO_POINTER(struct matrix, parent->pack, pp->t.mat);
    				break;
    			}
    		}
    
    		if (parent_mat == NULL && child_mat == NULL)
    			return;
    
    		if (parent_mat) {
    			matrix_mul(&tmp, parent_mat, mat);
    		} else {
    			tmp = *mat;
    		}
    
    		if (child_mat) {
    			matrix_mul(mat, child_mat, &tmp);
    		} else {
    			*mat = tmp;
    		}
    	} else {
    		matrix_identity(mat);
    	}
    }
    
    // aabb
    
    static void
    poly_aabb(int n, const int32_t * point, struct srt *srt, struct matrix *ts, int aabb[4]) {
    	struct matrix mat;
    	if (ts == NULL) {
    		matrix_identity(&mat);
    	} else {
    		mat = *ts;
    	}
    	matrix_srt(&mat, srt);
    	int *m = mat.m;
    
    	int i;
    	for (i=0;i<n;i++) {
    		int x = point[i*2];
    		int y = point[i*2+1];
    
    		int xx = (x * m[0] + y * m[2]) / 1024 + m[4];
    		int yy = (x * m[1] + y * m[3]) / 1024 + m[5];
    
    		if (xx < aabb[0])
    			aabb[0] = xx;
    		if (xx > aabb[2])
    			aabb[2] = xx;
    		if (yy < aabb[1])
    			aabb[1] = yy;
    		if (yy > aabb[3])
    			aabb[3] = yy;
    	}
    }
    
    static inline void
    quad_aabb(struct pack_picture * pic, struct srt *srt, struct matrix *ts, int aabb[4]) {
    	int i;
    	for (i=0;i<pic->n;i++) {
    		poly_aabb(4, pic->rect[i].screen_coord, srt, ts, aabb);
    	}
    }
    
    static inline void
    polygon_aabb(struct sprite_pack * pack, struct pack_polygon_data * polygon, struct srt *srt, struct matrix *ts, int aabb[4]) {
    	int i;
    	for (i=0;i<polygon->n;i++) {
    		struct pack_poly_data * poly = &polygon->poly[i];
    		int32_t * screen_coord = OFFSET_TO_POINTER(int32_t, pack, poly->screen_coord);
    		poly_aabb(poly->n, screen_coord, srt, ts, aabb);
    	}
    }
    
    static inline void
    label_aabb(struct pack_label *label, struct srt *srt, struct matrix *ts, int aabb[4]) {
    	int32_t point[] = {
    		0,0,
    		label->width * SCREEN_SCALE, 0,
    		0, label->height * SCREEN_SCALE,
    		label->width * SCREEN_SCALE, label->height * SCREEN_SCALE,
    	};
    	poly_aabb(4, point, srt, ts, aabb);
    }
    
    static inline void
    panel_aabb(struct pack_pannel *panel, struct srt *srt, struct matrix *ts, int aabb[4]) {
    	int32_t point[] = {
    		0,0,
    		panel->width * SCREEN_SCALE, 0,
    		0, panel->height * SCREEN_SCALE,
    		panel->width * SCREEN_SCALE, panel->height * SCREEN_SCALE,
    	};
    	poly_aabb(4, point, srt, ts, aabb);
    }
    
    static int
    child_aabb(struct sprite *s, struct srt *srt, struct matrix * mat, int aabb[4]) {
    	struct matrix temp;
    	struct matrix *t = mat_mul(s->t.mat, mat, &temp);
    	switch (s->type) {
    	case TYPE_PICTURE:
    		quad_aabb(s->s.pic, srt, t, aabb);
    		return 0;
    	case TYPE_POLYGON:
    		polygon_aabb(s->pack, s->s.poly, srt, t, aabb);
    		return 0;
    	case TYPE_LABEL:
    		label_aabb(s->s.label, srt, t, aabb);
    		return 0;
    	case TYPE_ANIMATION:
    		break;
    	case TYPE_PANNEL:
    		panel_aabb(s->s.pannel, srt, t, aabb);
    		return s->data.scissor;
    	default:
    		// todo : invalid type
    		return 0;
    	}
    	// draw animation
    	struct pack_animation *ani = s->s.ani;
    	int frame = get_frame(s);
    	if (frame < 0) {
    		return 0;
    	}
    	struct pack_frame * pf = OFFSET_TO_POINTER(struct pack_frame, s->pack, ani->frame);
    	pf = &pf[frame];
    	int i;
    	for (i=0;i<pf->n;i++) {
    		struct pack_part *pp = OFFSET_TO_POINTER(struct pack_part, s->pack, pf->part);
    		pp = &pp[i];
    		int index = pp->component_id;
    		struct sprite * child = s->data.children[index];
    		if (child == NULL || (child->flags & SPRFLAG_INVISIBLE)) {
    			continue;
    		}
    		struct matrix temp2;
    		struct matrix *ct = mat_mul(OFFSET_TO_POINTER(struct matrix, s->pack, pp->t.mat), t, &temp2);
    		if (child_aabb(child, srt, ct, aabb))
    			break;
    	}
    	return 0;
    }
    
    void
    sprite_aabb(struct sprite *s, struct srt *srt, bool world_aabb, int aabb[4]) {
    	int i;
    	if ((s->flags & SPRFLAG_INVISIBLE) == 0) {
    		struct matrix tmp;
    		if (world_aabb) {
    			sprite_matrix(s, &tmp);
    		} else {
    			matrix_identity(&tmp);
    		}
    		aabb[0] = INT_MAX;
    		aabb[1] = INT_MAX;
    		aabb[2] = INT_MIN;
    		aabb[3] = INT_MIN;
    		child_aabb(s,srt,&tmp,aabb);
    		for (i=0;i<4;i++)
    			aabb[i] /= SCREEN_SCALE;
    	} else {
    		for (i=0;i<4;i++)
    			aabb[i] = 0;
    	}
    }
    
    // test
    
    static int
    test_quad(struct pack_picture * pic, int x, int y) {
    	int p;
    	for (p=0;p<pic->n;p++) {
    		struct pack_quad *pq = &pic->rect[p];
    		int maxx,maxy,minx,miny;
    		minx= maxx = pq->screen_coord[0];
    		miny= maxy = pq->screen_coord[1];
    		int i;
    		for (i=2;i<8;i+=2) {
    			int x = pq->screen_coord[i];
    			int y = pq->screen_coord[i+1];
    			if (x<minx)
    				minx = x;
    			else if (x>maxx)
    				maxx = x;
    			if (y<miny)
    				miny = y;
    			else if (y>maxy)
    				maxy = y;
    		}
    		if (x>=minx && x<=maxx && y>=miny && y<=maxy)
    			return 1;
    	}
    	return 0;
    }
    
    static int
    test_polygon(struct sprite_pack *pack, struct pack_polygon_data * poly,  int x, int y) {
    	int p;
    	for (p=0;p<poly->n;p++) {
    		struct pack_poly_data *pp = &poly->poly[p];
    		int maxx,maxy,minx,miny;
    		int32_t * screen_coord = OFFSET_TO_POINTER(int32_t, pack, pp->screen_coord);
    		minx= maxx = screen_coord[0];
    		miny= maxy = screen_coord[1];
    		int i;
    		for (i=1;i<pp->n;i++) {
    			int x = screen_coord[i*2+0];
    			int y = screen_coord[i*2+1];
    			if (x<minx)
    				minx = x;
    			else if (x>maxx)
    				maxx = x;
    			if (y<miny)
    				miny = y;
    			else if (y>maxy)
    				maxy = y;
    		}
    		if (x>=minx && x<=maxx && y>=miny && y<=maxy) {
    			return 1;
    		}
    	}
    	return 0;
    }
    
    static int
    test_label(struct pack_label *label, int x, int y) {
    	x /= SCREEN_SCALE;
    	y /= SCREEN_SCALE;
    	return x>=0 && x<label->width && y>=0 && y<label->height;
    }
    
    static int
    test_pannel(struct pack_pannel *pannel, int x, int y) {
    	x /= SCREEN_SCALE;
    	y /= SCREEN_SCALE;
    	return x>=0 && x<pannel->width && y>=0 && y<pannel->height;
    }
    
    static int test_child(struct sprite *s, struct srt *srt, struct matrix * ts, int x, int y, struct sprite ** touch);
    
    static int
    check_child(struct sprite *s, struct srt *srt, struct matrix * t, struct pack_frame * pf, int i, int x, int y, struct sprite ** touch) {
    	struct pack_part *pp = OFFSET_TO_POINTER(struct pack_part, s->pack, pf->part);
    	pp = &pp[i];
    	int index = pp->component_id;
    	struct sprite * child = s->data.children[index];
    	if (child == NULL || (child->flags & SPRFLAG_INVISIBLE)) {
    		return 0;
    	}
    	struct matrix temp2;
    	struct matrix *ct = mat_mul(OFFSET_TO_POINTER(struct matrix, s->pack, pp->t.mat), t, &temp2);
    	struct sprite *tmp = NULL;
    	int testin = test_child(child, srt, ct, x, y, &tmp);
    	if (testin) {
    		// if child capture message, return it
    		*touch = tmp;
    		return 1;
    	}
    	if (tmp) {
    		// if child not capture message, but grandson (tmp) capture it, mark it
    		*touch = tmp;
    	}
    	return 0;
    }
    
    /*
    	return 1 : test succ
    		0 : test failed, but *touch capture the message
     */
    static int
    test_animation(struct sprite *s, struct srt *srt, struct matrix * t, int x, int y, struct sprite ** touch) {
    	struct pack_animation *ani = s->s.ani;
    	int frame = get_frame(s);
    	if (frame < 0) {
    		return 0;
    	}
    	struct pack_frame * pf = OFFSET_TO_POINTER(struct pack_frame, s->pack, ani->frame);
    	pf = &pf[frame];
    	int start = pf->n-1;
    	do {
    		int scissor = -1;
    		int i;
    		// find scissor and check it first
    		for (i=start;i>=0;i--) {
    			struct pack_part *pp = OFFSET_TO_POINTER(struct pack_part, s->pack, pf->part);
    			pp = &pp[i];
    			int index = pp->component_id;
    			struct sprite * c = s->data.children[index];
    			if (c == NULL || (c->flags & SPRFLAG_INVISIBLE)) {
    				continue;
    			}
    			if (c->type == TYPE_PANNEL && c->data.scissor) {
    				scissor = i;
    				break;
    			}
    
    		}
    		if (scissor >=0) {
    			struct sprite *tmp = NULL;
    			check_child(s, srt, t, pf, scissor, x, y, &tmp);
    			if (tmp == NULL) {
    				start = scissor - 1;
    				continue;
    			}
    		} else {
    			scissor = 0;
    		}
    		for (i=start;i>=scissor;i--) {
    			int hit = check_child(s, srt, t,  pf, i, x, y, touch);
    			if (hit)
    				return 1;
    		}
    		start = scissor - 1;
    	} while(start>=0);
    	return 0;
    }
    
    static int
    test_child(struct sprite *s, struct srt *srt, struct matrix * ts, int x, int y, struct sprite ** touch) {
    	struct matrix temp;
    	struct matrix *t = mat_mul(s->t.mat, ts, &temp);
    	if (s->type == TYPE_ANIMATION) {
    		struct sprite *tmp = NULL;
    		int testin = test_animation(s , srt, t, x,y, &tmp);
    		if (testin) {
    			*touch = tmp;
    			return 1;
    		} else if (tmp) {
    			if (s->flags & SPRFLAG_MESSAGE) {
    				*touch = s;
    				return 1;
    			} else {
    				*touch = tmp;
    				return 0;
    			}
    		}
    	}
    	struct matrix mat;
    	if (t == NULL) {
    		matrix_identity(&mat);
    	} else {
    		mat = *t;
    	}
    	matrix_srt(&mat, srt);
    	struct matrix imat;
    	if (matrix_inverse(&mat, &imat)) {
    		// invalid matrix
    		*touch = NULL;
    		return 0;
    	}
    	int *m = imat.m;
    
    	int xx = (x * m[0] + y * m[2]) / 1024 + m[4];
    	int yy = (x * m[1] + y * m[3]) / 1024 + m[5];
    
    	int testin;
    	struct sprite * tmp = s;
    	switch (s->type) {
    	case TYPE_PICTURE:
    		testin = test_quad(s->s.pic, xx, yy);
    		break;
    	case TYPE_POLYGON:
    		testin = test_polygon(s->pack, s->s.poly, xx, yy);
    		break;
    	case TYPE_LABEL:
    		testin = test_label(s->s.label, xx, yy);
    		break;
    	case TYPE_PANNEL:
    		testin = test_pannel(s->s.pannel, xx, yy);
    		break;
    	case TYPE_ANCHOR:
    		*touch = NULL;
    		return 0;
    	default:
    		// todo : invalid type
    		*touch = NULL;
    		return 0;
    	}
    
    	if (testin) {
    		*touch = tmp;
    		return s->flags & SPRFLAG_MESSAGE;
    	} else {
    		*touch = NULL;
    		return 0;
    	}
    }
    
    struct sprite *
    sprite_test(struct sprite *s, struct srt *srt, int x, int y) {
    	struct sprite *tmp = NULL;
    	int testin = test_child(s, srt, NULL, x, y, &tmp);
    	if (testin) {
    		return tmp;
    	}
    	if (tmp) {
    		return s;
    	}
    	return NULL;
    }
    
    static inline int
    propagate_frame(struct sprite *s, int i, bool force_child) {
    	struct sprite *child = s->data.children[i];
    	if (child == NULL || child->type != TYPE_ANIMATION) {
    		return 0;
    	}
    	if (child->flags & SPRFLAG_FORCE_INHERIT_FRAME) {
    		return 1;
    	}
    	struct pack_animation * ani = s->s.ani;
    	if (ani->component[i].id == ANCHOR_ID) {
    		return 0;
    	}
    	if (force_child) {
    		return 1;
    	}
    	if (ani->component[i].name == 0) {
    		return 1;
    	}
    	return 0;
    }
    
    int
    sprite_setframe(struct sprite *s, int frame, bool force_child) {
    	if (s == NULL || s->type != TYPE_ANIMATION)
    		return 0;
    	s->frame = frame;
    	int total_frame = s->total_frame;
    	int i;
    	struct pack_animation * ani = s->s.ani;
    	for (i=0;i<ani->component_number;i++) {
    		if (propagate_frame(s, i, force_child)) {
    			int t = sprite_setframe(s->data.children[i],frame, force_child);
    			if (t > total_frame) {
    				total_frame = t;
    			}
    		}
    	}
    	return total_frame;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648
    • 649
    • 650
    • 651
    • 652
    • 653
    • 654
    • 655
    • 656
    • 657
    • 658
    • 659
    • 660
    • 661
    • 662
    • 663
    • 664
    • 665
    • 666
    • 667
    • 668
    • 669
    • 670
    • 671
    • 672
    • 673
    • 674
    • 675
    • 676
    • 677
    • 678
    • 679
    • 680
    • 681
    • 682
    • 683
    • 684
    • 685
    • 686
    • 687
    • 688
    • 689
    • 690
    • 691
    • 692
    • 693
    • 694
    • 695
    • 696
    • 697
    • 698
    • 699
    • 700
    • 701
    • 702
    • 703
    • 704
    • 705
    • 706
    • 707
    • 708
    • 709
    • 710
    • 711
    • 712
    • 713
    • 714
    • 715
    • 716
    • 717
    • 718
    • 719
    • 720
    • 721
    • 722
    • 723
    • 724
    • 725
    • 726
    • 727
    • 728
    • 729
    • 730
    • 731
    • 732
    • 733
    • 734
    • 735
    • 736
    • 737
    • 738
    • 739
    • 740
    • 741
    • 742
    • 743
    • 744
    • 745
    • 746
    • 747
    • 748
    • 749
    • 750
    • 751
    • 752
    • 753
    • 754
    • 755
    • 756
    • 757
    • 758
    • 759
    • 760
    • 761
    • 762
    • 763
    • 764
    • 765
    • 766
    • 767
    • 768
    • 769
    • 770
    • 771
    • 772
    • 773
    • 774
    • 775
    • 776
    • 777
    • 778
    • 779
    • 780
    • 781
    • 782
    • 783
    • 784
    • 785
    • 786
    • 787
    • 788
    • 789
    • 790
    • 791
    • 792
    • 793
    • 794
    • 795
    • 796
    • 797
    • 798
    • 799
    • 800
    • 801
    • 802
    • 803
    • 804
    • 805
    • 806
    • 807
    • 808
    • 809
    • 810
    • 811
    • 812
    • 813
    • 814
    • 815
    • 816
    • 817
    • 818
    • 819
    • 820
    • 821
    • 822
    • 823
    • 824
    • 825
    • 826
    • 827
    • 828
    • 829
    • 830
    • 831
    • 832
    • 833
    • 834
    • 835
    • 836
    • 837
    • 838
    • 839
    • 840
    • 841
    • 842
    • 843
    • 844
    • 845
    • 846
    • 847
    • 848
    • 849
    • 850
    • 851
    • 852
    • 853
    • 854
    • 855
    • 856
    • 857
    • 858
    • 859
    • 860
    • 861
    • 862
    • 863
    • 864
    • 865
    • 866
    • 867
    • 868
    • 869
    • 870
    • 871
    • 872
    • 873
    • 874
    • 875
    • 876
    • 877
    • 878
    • 879
    • 880
    • 881
    • 882
    • 883
    • 884
    • 885
    • 886
    • 887
    • 888
    • 889
    • 890
    • 891
    • 892
    • 893
    • 894
    • 895
    • 896
    • 897
    • 898
    • 899
    • 900
    • 901
    • 902
    • 903
    • 904
    • 905
    • 906
    • 907
    • 908
    • 909
    • 910
    • 911
    • 912
    • 913
    • 914
    • 915
    • 916
    • 917
    • 918
    • 919
    • 920
    • 921
    • 922
    • 923
    • 924
    • 925
    • 926
    • 927
    • 928
    • 929
    • 930
    • 931
    • 932
    • 933
    • 934
    • 935
    • 936
    • 937
    • 938
    • 939
    • 940
    • 941
    • 942
    • 943
    • 944
    • 945
    • 946
    • 947
    • 948
    • 949
    • 950
    • 951
    • 952
    • 953
    • 954
    • 955
    • 956
    • 957
    • 958
    • 959
    • 960
    • 961
    • 962
    • 963
    • 964
    • 965
    • 966
    • 967
    • 968
    • 969
    • 970
    • 971
    • 972
    • 973
    • 974
    • 975
    • 976
    • 977
    • 978
    • 979
    • 980
    • 981
    • 982
    • 983
    • 984
    • 985
    • 986
    • 987
    • 988
    • 989
    • 990
    • 991
    • 992
    • 993
    • 994
    • 995
    • 996
    • 997
    • 998
    • 999
    • 1000
    • 1001
    • 1002
    • 1003
    • 1004
    • 1005
    • 1006
    • 1007
    • 1008
    • 1009
    • 1010
    • 1011
    • 1012
    • 1013
    • 1014
    • 1015
    • 1016
    • 1017
    • 1018
    • 1019
    • 1020
    • 1021
    • 1022
    • 1023
    • 1024
    • 1025
    • 1026
    • 1027
    • 1028
    • 1029
    • 1030
    • 1031
    • 1032
    • 1033
    • 1034
    • 1035
    • 1036
    • 1037
    • 1038
    • 1039
    • 1040
    • 1041
    • 1042
    • 1043
    • 1044
    • 1045
    • 1046
    • 1047
    • 1048
    • 1049
    • 1050
    • 1051
    • 1052
    • 1053
    • 1054
    • 1055
    • 1056
    • 1057
    • 1058
    • 1059
    • 1060
    • 1061
    • 1062
    • 1063
    • 1064
    • 1065
    • 1066
    • 1067
    • 1068
    • 1069
    • 1070
    • 1071
    • 1072
    • 1073
    • 1074
    • 1075
    • 1076
    • 1077
    • 1078
    • 1079
    • 1080
    • 1081
    • 1082
    • 1083
    • 1084
    • 1085
    • 1086
    • 1087
    • 1088
    • 1089
    • 1090
    • 1091
    • 1092
    • 1093
    • 1094
    • 1095
    • 1096
    • 1097
    • 1098
    • 1099

    雷军大学期间写的汇编代码

    雷军1994年写的代码,用的编译器是TASM 3.0,Borland公司推出的。需要在dos环境下,用tasm 汇编成obj,然后使用tlink进行链接,最终生成COM可执行程序。雷军把自己的汇编绝学写进了《深入dos编程》一书中。想当初,求伯君,史玉柱还有鲍岳桥也是靠汇编,写出了名噪一时的中文处理系统。俱往矣,数风流人物,还看张一鸣。
    下面这段代码,用于清除内存的驻留程序。

    
    ;
    ; RI.ASM Revision 2.12 [ July 12, 1994 ]
    Revision equ 'V2.12 '
    ;
    ;
    ;
    ;  RAMinit Release 2.0 
    ;  Copyright (c) 1989-1994 by Yellow Rose Software Co.
    ;  Written by Mr. Leijun
    ;
    ;  Function:
    ;  Press HotKey to remove all TSR program after this program
    ;
    ;
     
    ; ..........................................................................
    ; Removed Softwares by RI:
    ; SPDOS v6.0F, WPS v3.0F
    ; Game Busters III, IV
    ; NETX ( Novell 3.11 )
    ; PC-CACHE
    ; Norton Cache
    ; Microsoft SmartDrv
    ; SideKick 1.56A
    ; MOUSE Driver
    ; Crazy (Monochrome simulate CGA program)
    ; RAMBIOS v2.0
    ; 386MAX Version 6.01
    ; ..........................................................................
    ; No cancel softwares:
    ; Windows 3.1 MSD
    ;
    ; No removed TSR softwares:
    ; MS-DOS fastopen
    ; Buffers, Files ... (QEMM 6.0)
    ; QCache (386MAX 6.01)
    ; ..........................................................................
    ;
    COMMENT
     
    V2.04 Use mouse driver software reset function to initiation mouse
    2/17/1993 by Mr. Lei and Mr. Feng
    V2.05 RI cannot work in Windows DOS prompt
    3/9/1993 by Mr. Lei
    V2.06 1. When XMS cannot allocate 1K memory, RI halts.
    2. RI repeat deallocates EMS memory.
    V2.07 HotKey Setup Error
    4/25/1993 by Mr. Lei
    V2.08 KB Buffer
    V2.10 1. Release high memory blocks (EMM386 QEMM386 S-ICE 386MAX)
    2. RI copies flag
    V2.12 1. Exists a critical error in Init 8259 procedure
    2. Save [40:F0--FF] user data area
     
     
     
    dosseg
    .model tiny
    .code
    locals @@
    org 100h
     
    Start: jmp Main
    org 103h
     
    True equ 1
    False equ 0
    MaxHandles equ 100h
     
    INT3 macro
    out 0ffh,al
    endm
    ;
    ; HotKey Status Test Var
    ; --------------- ---------------
    ;
    ; 7 6 5 4 3 2 1 0 417 418 496
    ; . . x . x . . . Left Alt is pressed 8 2
    ; x . . . x . . . Right Alt is pressed 8 8
    ; . . . x . x . . Left Ctrl is pressed 4 1
    ; . x . . . x . . Right Ctrl is pressed 4 4
    ; . . . . . . x . Left Shift is pressed 2
    ; . . . . . . . x Right Shift is pressed 1
    ;
    LeftAlt equ 00101000b
    RightAlt equ 10001000b
    LeftCtrl equ 00010100b
    RightCtrl equ 01000100b
    LeftShift equ 00000010b
    RightShift equ 00000001b
    HotKey db LeftCtrl or RightCtrl
     
    DataBegin dw 0
    NextDataSeg dw 0ffffh
    oldInt2F_addr dw 0, 0
    XMS_control dw 0, 0
    Handle_begin dw 0
    cvtOfs dw 0 ; DOS 3.0 equ 0 and above DOS 4.0 is 1
    org 104h
    db 0dh
    db Revision
    db ??date
    db 26
    org 114h
    tsrLength dw 0
    MachineID db 0FCh ; IBM PC/AT
     
    AuxHotKey db 0 ; 2Dh ; 'X' Scan Code
    AuxHotKeyName db 'X$ '
    Power db True
    Flag db '!'
    Kbd102 db 0
    NoFlag db 0
    StopFlag db 1
    DosEnv dw 0
    WorkSeg dw 0
    PrevDataSeg dw 0
    Copies db '1'
    old_8259 db 0 ; 21h port
    db 0 ; a1h port
     
    Status dw 0
    XMSbit equ 00000001b
    EMSbit equ 00000010b
    SKbit equ 10000000b
     
    GoINT1C: db 0eah
    oldInt1C_addr dw 0, 0
    newINT1C:
    test cs:Status, SKbit
    jnz GoINT1C
    cmp cs:StopFlag, 0
    jz @@0
    ;
    ; Mr. Lei 2/8/1993
    ; Problem: if WPS quit and reenter, old RI cann't control keyboard. ;
    push ds
    push ax
    xor ax, ax
    mov ds, ax
    mov ax, ds:[94]
    cmp ax, offset NewInt9
    pop ax
    pop ds
    jnz GoINT1C
    mov cs:StopFlag, 0
    @@0: push ax
    push ds
    push es
    xor ax, ax
    mov ds, ax
    mov es, ds:[94+2]
    cmp word ptr es:[101h], 'IE' ; 'LEI'
    jz @@1
    cli
    mov cs:StopFlag, 1
    mov ax, ds:[94]
    mov cs:oldINT9_addr2, ax
    mov ax, ds:[94+2]
    mov cs:oldINT9_addr2[2], ax
    mov ds:[94], offset newINT9_2
    mov ds:[94+2], cs
    sti
    @@1: pop es
    pop ds
    pop ax
    jmp GoINT1C
    ; ----------------------------------------------------------------------
    ; INT2F Func
    ;
    ; AX = C0D7h Return RI segment in AX
    ; AX = C0D8h Removes all TSR programs after RI
    ; AX = C0D9h Removes all TSR programs include RI
    ; AX = C0DAh Removes all RI copies
    ; ----------------------------------------------------------------------
    newINT2F:
    cmp ax, 0c0d7h ; LEI Hanzi GB Code
    jnz @@1
    push cs
    pop ax
    iret
    @@1: cmp ax, 0c0d7h+1
    jnz @@2
    jmp KeepSelf
    @@2: cmp ax, 0c0d7h+2
    jnz @@3
    jmp NoKeepSelf
    @@3: cmp ax, 0c0d7h+3
    jnz @@9
    mov cs:NextDataSeg, -1
    mov cs:Copies, '1'
    jmp NoKeepSelf
    @@9: jmp dword ptr cs:oldInt2F_addr
    CallInt9:
    ret
    newINT9_2:
    mov cs:NoFlag, 1
    pushf
    db 9ah ; call far ptr oldint9_addr
    oldInt9_Addr2 dw 0, 0
    jmp newINT9_proc
    newINT9:
    pushf
    db 9ah ; call far ptr oldint9_addr
    oldInt9_Addr dw 0, 0 cmp cs:NoFlag, 0
    jz newINT9_proc
    mov cs:NoFlag, 0
    iret
    newINT9_proc:
    cmp cs:Flag, '!' ; busy ?
    jnz @@0
    iret
    @@0:
    mov cs:Flag, '!' ; set busy flag
    push ax ; cmp hot key
    push bx
    push es
    mov ax,40h
    mov es,ax
    cmp cs:AuxHotKey, 0
    jz @@_1
    mov bx, es:[1ah]
    cmp bx, es:[1ch]
    jz @@10
    push bx
    mov bl, es:[bx+1]
    cmp bl, cs:AuxHotKey
    pop bx
    jnz @@10
    @@_1:
    mov ah,es:[17h] ; test CTRL SHIFT ALT
    mov al,cs:HotKey
    push ax
    and ax,0f0fh
    cmp al,ah
    pop ax
    jnz @@10 cmp cs:Kbd102, True
    jnz @@1
    shr al, 1
    shr al, 1
    shr al, 1
    shr al, 1
    push ax
    mov ah, es:[18h]
    and ax, 303h
    cmp al, ah
    pop ax
    jnz @@10
    mov ah, es:[96h]
    shr ax, 1
    shr ax, 1
    and ax, 303h
    cmp al, ah
    jnz @@10 cmp cs:AuxHotKey, 0
    jz @@_3
    inc bx
    inc bx
    cmp bx, 3eh
    jb @@_2
    mov bx, 1eh
    @@_2:
    mov es:[1ah], bx
    @@_3:
    call IsWinDos
    or ax, ax
    jz @@1
    call Beep
    @@10:
    sti
    pop es
    pop bx
    pop ax
    mov cs:Flag, ' ' ; no busy
    iret
    @@1: ; OK
    pop es
    pop bx
    pop ax
    KeepSelf:
    call RemoveTSR
    push es
    mov es,cs:WorkSeg
    mov dx,es:tsrLength
    mov di,dx
    mov al,0h ; Aug 24, 1993
    mov cx,100h
    rep stosb
    pop es
    int 27h
    NoKeepSelf:
    mov ax,0e07h
    int 10h
    mov cs:clsStr, 47h ; Color (White in Red)
    call RemoveTSR
    dec cs:Copies
    call RestoreSelfIntVec
    push es
    cmp cs:PrevDataSeg, 0
    jz @@1
    mov es, cs:PrevDataSeg
    mov es:NextDataSeg, -1
    @@1: pop es
    mov ax, 4c00h
    int 21h
    ; ---------------------------------------------------------------------------
    IsWinDOS:
    mov ax, 1600h
    int 2fh
    cmp al, 01h
    jz @@9 cmp al, 0ffh
    jz @@9 ; Windows/386 Version 2.X
    cmp al, 00h
    jz @@1 cmp al, 80h
    jnz @@9 ; Windows 3 in enhanced mode
    ; Version number in AL/AH
    @@1:
    mov ax, 4680h
    int 2fh
    cmp al, 80h
    jnz @@9
    xor ax, ax
    jmp @@10
    @@9: mov ax, 1
    @@10: ret
    ; -----------------------------------------------------------------------
    RestoreSelfIntVec:
    cmp Copies, '0'
    jz @@0
    ret
    @@0:
    cli
    push cs
    pop ds
    xor ax, ax
    mov es, ax
    mov si, offset oldInt9_Addr
    mov di, 94
    movsw
    movsw
    mov si, offset oldInt2F_Addr
    mov di, 2Fh4
    movsw
    movsw
    mov si, offset oldInt1C_Addr
    mov di, 1Ch4
    movsw
    movsw
    sti
    ret
    ; ------------- KERNEL PROGRAM ----------------------------------------------
    RemoveTSR:
    pop ax
    cli ; Set stack
    mov sp, cs
    mov ss, sp
    mov sp, 100h
    sti
    push ax
    cmp cs:Power, True
    jnz @@1
    call Init8259
    @@1:
    push cs
    pop ds
    @@_0:
    mov ax,ds:NextDataSeg
    cmp ax, -1
    jz @@_1
    mov cs:PrevDataSeg, ds
    mov ds, ax
    jmp @@_0
    @@_1: mov si,ds:DataBegin
    mov cs:WorkSeg, ds
    lodsw
    cmp ax, 'XX'
    jz @@_2
    call Beep
    ret
    @@_2:
    call RestoreEnvStr
    call RestoreMCB ; restore current mcb
    call CloseFiles
    call RestorePort
    call RestoreLEDs
    call RestoreVecList ; Restore vectors list
    call RestoreFloppyParam
    cmp cs:Power, True
    jnz @@2
    call RestoreCVTchain ; Restore cvt chain
    call RestoreMemoryManager
    @@2:
    call RestoreBiosData
    call Enable8259
    mov ah, 1 int 16h
    call RestoreClockSpeed
    call CloseSpeaker
    call ResetDisk
    call UpdateTime
    call ClosePRN
    mov bx,cs:WorkSeg
    mov ah,50h
    int 21h ; Set PSP segment
    mov ax,3 int 10h ; Set display mode
    call InitPRN
    call InitMouse
    mov al, cs:Copies
    cmp al, '1'
    ja @@_sh1
    mov cs:ShowCopies, ''
    jmp @@_sh2
    @@_sh1: mov cs:ShowCopies, al
    @@_sh2:
    mov si, offset clsStr
    call ColorPrintStr
    mov cs:Flag, ' ' ; no busy
    cmp Copies, '1'
    jnz @@_end
    mov cs:StopFlag, 0
    @@_end:
    call ClearKB_buffer
    ret
    Beep:
    mov ax,0e07h
    int 10h
    ret
    ; #########################################################################
    ClearKB_Buffer:
    push es
    push bx
    mov bx, 0040h
    mov es, bx
    cli
    mov bx, es:[1ah]
    mov es:[1ch], bx
    sti
    pop bx
    pop es
    ret
    Init8259:
    ; cmp cs:Copies, '1'
    ; jz @@1
    ; ret
    @@1:
    cmp cs:MachineID, 0fch
    ja @@pc_xt
    @@AT:
    mov bx,870h ;
    mov al,0 ;
    out 0F1h,al ;
    jcxz $+2
    jcxz $+2
    mov al,11h ; ICW1
    out 0A0h,al
    jcxz $+2
    jcxz $+2
    out 20h,al
    jcxz $+2
    jcxz $+2
    mov al,bl ; ICW2
    out 0A1h,al
    jcxz $+2
    jcxz $+2
    mov al,bh
    out 21h,al
    jcxz $+2
    jcxz $+2
    mov al,2 ; ICW3
    out 0A1h,al
    jcxz $+2
    jcxz $+2
    mov al,4
    out 21h,al
    jcxz $+2
    jcxz $+2
    mov al,1 ; ICW4
    out 0A1h,al
    jcxz $+2
    jcxz $+2
    out 21h,al
    jcxz $+2
    jcxz $+2
    mov al,0FFh ; OCW1
    out 0A1h,al
    jcxz $+2
    jcxz $+2
    out 21h,al
    ret
    @@PC_XT:
    mov al,13h ; ICW1
    out 20h,al
    jcxz $+2
    jcxz $+2
    mov al,8 ; ICW2
    out 21h,al
    jcxz $+2
    jcxz $+2
    mov al,9 ; ICW4
    out 21h,al
    jcxz $+2
    jcxz $+2
    mov al,0FFh ; OCW1
    out 21h,al
    ret
    Enable8259:
    mov ax, word ptr cs:old_8259
    out 021h,al
    jcxz $+2
    jcxz $+2
    mov al,ah
    out 0a1h,al ; DEC PC Bus Mouse
    ret ; July 1994 by Mr. Lei
    ; -------------------------------------------------------------------------
    RestoreBiosData:
    lodsw
    cmp ax, '--'
    jz @@1
    call Beep
    ret
    @@1: push es
    push di
    mov di, 40h
    mov es, di
    mov di, 10h
    movsw
    mov di, 0a8h ; [40h:a8h]
    movsw
    movsw
    mov di, 49h
    mov cx, 1dh
    rep movsb
    mov di, 0f0h ; User data
    mov cx, 8
    rep movsw
    pop di
    pop es
    ret
    ; -------------------------------------------------------------------------
    RestoreMCB:
    push ds
    push es
    lodsw ; 'MZ'
    @@0: lodsw
    cmp ax, 'MM'
    jz @@1
    mov es,ax
    xor di,di
    movsb
    movsw
    movsw
    inc ax
    mov bx, ds
    cmp ax, bx
    jz @@10
    mov byte ptr es:[8], 0 ; Aug 24, 1993
    @@10: cmp byte ptr es:[0], 'Z'
    jnz @@0
    mov byte ptr es:[10h], 0
    jmp @@0
    @@1:
    pop es
    pop ds
    ret
    ; -------------------------------------------------------------------------
    CloseFiles:
    mov ax, 5 ; Begin handle
    push ds
    push si
    mov cx, 15 ; Max handle
    sub cx, ax
    inc cx
    mov bx, ax
    @@1: push bx
    push cx
    mov ah, 3eh
    int 21h
    pop cx
    pop bx
    inc bx
    loop @@1
    pop si
    pop ds
    ret
    ; -------------------------------------------------------------------------
    RestorePort:
    mov di, 40h ; restore port
    mov es, di
    xor di, di
    mov cx, 8
    rep movsw
    ret
    ; -------------------------------------------------------------------------
    RestoreLEDs:
    lodsb
    and al, 11110000b ; LED status
    mov ah, es:[17h]
    and ah, 00001111b
    or ah, al
    and ah, 0f0h ; Clear CTRL ALT SHIFT
    mov es:[17h], ah
    ret
    ; -------------------------------------------------------------------------
    RestoreEnvStr:
    lodsw
    push si
    push di
    push ds
    push es
    mov es, cs:DosEnv
    mov ds, ax
    xor si, si
    mov di, si
    @@0: lodsb
    or al, al
    jnz @@1 cmp byte ptr ds:[si], 0
    jz @@2
    @@1: stosb
    jmp @@0
    @@2: stosb
    stosb
    pop es
    pop ds
    pop di
    pop si
    ret
    ; -----------------------------------------------------------------------
    RestoreVecList:
    xor ax,ax
    mov di,ax
    mov es,ax
    mov cx,100h
    @@0: lodsw
    xchg dx, ax
    lodsw
    cmp dx, 'EL'
    jnz @@1 cmp al, 'I'
    jnz @@1
    sub cl, ah
    push cx
    mov cl, ah
    mov ax, es:[di-4]
    mov dx, es:[di-2]
    @@a: stosw
    xchg ax, dx
    stosw
    xchg ax, dx
    loop @@a
    pop cx
    or cx, cx
    jz @@9
    jmp @@0
    @@1:
    xchg ax, dx
    stosw
    xchg ax, dx
    stosw
    loop @@0
    @@9:
    ret
    ;----------------------------------------------------------------------------
    RestoreFloppyParam: ; Mr. Lei 2/10/1992
    push es
    push ax
    xor ax, ax
    mov es, ax
    mov byte ptr es:[525h], 2
    pop ax
    pop es
    ret
    ;---------------------------------------------------------------------------
    RestoreCVTchain:
    lodsw
    cmp ax, 'VC'
    jz @@_0
    call Beep
    ret
    @@_0:
    push ax
    push cx
    push es
    ; -----------------------------------------------------------------
    lodsw ; DPB
    mov di, ax
    lodsw
    mov es, ax
    @@1: lodsb
    inc di
    stosb
    add di, cs:cvtOfs
    add di, 10h
    movsw
    movsw
    les di, es:[di+2]
    cmp di, -1
    jnz @@1
    ; -----------------------------------------------------------------
    lodsw ; DCB
    mov di, ax
    lodsw
    mov es, ax
    xor ax, ax
    dec ax
    stosw
    ; -----------------------------------------------------------------
    lodsw ; Device Driver Chain
    mov di, ax
    lodsw
    mov es, ax
    xor cx, cx
    @@9: push di
    mov cl, 5
    rep movsw
    pop di
    les di, es:[di]
    mov ax, di
    inc ax
    jnz @@9
    pop es
    pop cx
    pop ax
    ret
    ; ----------------------------------------------------------------------------
    RestoreMemoryManager:
    test cs:Status, XMSbit
    jz @@1
    call LoadXMSstatus
    @@1:
    test cs:Status, EMSbit
    jz @@2
    call LoadEMSstatus
    @@2:
    ret
    LoadEMSstatus:
    lodsw
    cmp ax, 'ME'
    jz @@_0
    call Beep
    ret
    @@_0:
    lodsw
    mov cx, ax
    xor dx, dx
    @@_1: push ds
    push si
    push dx
    push cx
    @@0: cmp dx, ds:[si]
    jz @@1
    add si, 4
    loop @@0
    push cx
    mov cx, 5
    @@0: mov ah, 45h ; Deallocate Handle and Memory
    int 67h
    or ah, ah
    jz @@1
    loop @@0
    @@1: pop cx
    @@1:
    pop cx
    pop dx
    pop si
    pop ds
    inc dx
    cmp dx, 100h
    jb @@_1
    shl cx, 1
    shl cx, 1
    add si, cx
    ret
    LoadXMSstatus:
    lodsw
    cmp ax, 'MX'
    jz @@_0
    call Beep
    ret
    @@_0:
    lodsw
    mov cx, ax
    jcxz @@5
    @@1:
    lodsw
    mov dx, ax
    @@2: push dx
    mov ah, 0ah ; free
    call dword ptr cs:xms_control
    or ax, ax
    pop dx
    jnz @@4 cmp bl, 0abh
    jnz @@4
    push dx
    mov ah, 0dh ; unlock
    call dword ptr cs:xms_control
    or ax, ax
    pop dx
    jmp @@2
    @@4: loop @@1
    @@5: ret
    endp
    ; -----------------------------------------------------------------------
    CloseSpeaker:
    in al, 61h
    and al, 0fch
    out 61h, al
    ret
    ; -----------------------------------------------------------------------
    RestoreClockSpeed:
    mov al, 00110110b
    out 43h, al
    xor ax, ax
    out 40h, al
    out 40h, al
    ret
    ; -----------------------------------------------------------------------
    ResetDisk:
    xor ax, ax
    xor dx, dx
    int 13h ; Restore A
    inc dx
    int 13h ; Restore B
    mov dl, 80h
    int 13h ; Restore C
    ret
    ; --------------------------------------------------------------------------
    ClosePRN:
    mov ah, 51h ; Get PSP seg
    int 21h
    mov es, bx
    mov ax, es:[16h] ; Prev PSP seg
    cmp ax, bx
    jnz @@9
    mov ax, 3e00h ; COMMAND
    mov bx, 4 int 21h
    @@9:
    ret
    InitPRN:
    mov ax, 3e00h
    mov bx, 4 ; PRN
    int 21h
    mov ax, 3d01h
    mov dx, offset PRNname
    push cs
    pop ds
    int 21h
    ret
    PRNname db 'PRN',0
    InitMouse: ; 2/16/1993 by Mr. Lei
    push es
    xor ax, ax
    mov es, ax
    cmp word ptr es:[33h4+2], 0
    jz @@0 cmp word ptr es:[33h4], 0
    jz @@0
    mov ax, 21h
    int 33h ; Hook Mouse Interrupt
    @@0: pop es
    ret
    ; ------------- CMOS CLOCK set to System -----------------------------------
    UpdateTime:
    call GetRealTime
    mov ah, 2dh
    int 21h
    ret
    GetRealTime:
    mov ah,2 int 1Ah
    mov al,ch
    call bcdxchg
    mov ch,al
    mov al,cl
    call bcdxchg
    mov cl,al
    mov al,dh
    call bcdxchg
    mov dh,al
    mov dl,0
    ret
    BCDxchg:
    push ax
    push cx
    mov cl,4
    shr al,cl
    pop cx
    mov bl,0Ah
    mul bl
    pop bx
    and bl,0Fh
    add al,bl
    ret
    ; -----------------------------------------------------------------------
    ; Display string
    ColorPrintStr:
    lodsb
    mov bh, al ; color
    xor cx, cx
    mov dx, 014fh
    mov ax, 0600h
    int 10h
    mov ah, 02 ; GotoXY (0, 0)
    xor dx, dx
    mov bh, 0 int 10h
    PrintStr:
    push cs
    pop ds
    xor bx, bx
    @@1: lodsb
    cmp al, '$'
    jz @@2
    or al, al
    jz @@2
    mov ah, 0eh
    int 10h
    jmp short @@1
    @@2: mov al, cs:clsStrcolor
    mov cs:clsStr, al
    ret
    ; -----------------------------------------------------------------------
    Self dw 0
    clsStrcolor db 17h
    clsStr db 17h ; Color (White in Blue)
    db ' RAMinit Version 2.12 (c) 1989-1994 by KingSoft Ltd. Mr. Leijun'
    db 0dh,0ah
    db ' ['
    ShowCopies db ''
    db '] Activate...',0ah,0dh,'$'
    endTSR equ $
    mcbList equ offset endTSR + 2 + 2
    vecList equ mcbList + 710 + 2 + 10h + 1 + 400h
    devLink equ vecList + 4 + 5  26 + 4 + 10  30h + 4
    xmsList equ devLink + 2 + MaxHandles  2
    emsList equ xmsList + 4 + 1024
    crtMode equ emsList + 2 + 1Dh + 4 + 10h
    tsrLen equ crtMode + 1
    ;
    ; DOS Environment Reserved by RI
    ; --------------------------------------------------
    ; Flag 'XX' 2 bytes
    ; Environment Segment 1 word
    ; Free MCBs <=710 bytes
    ; MCB segment 1 word
    ; MCB 5 bytes
    ; End flag 'MM' 1 word
    ; COM LPT ports 10h bytes
    ; LEDs status 1 bytes
    ; Packed vectors list <=400h bytes
    ; Flag 'CV' 2 bytes
    ; CVT First DPB pointer 4 bytes
    ; DPBs data <=526 bytes
    ; First DCB pointer 4 bytes
    ; Pointer to NUL 4 bytes
    ; All device driver datas <=30h10 bytes
    ; Flag 'XM' 2 bytes
    ; XMS free handle counter 2 bytes
    ; EMS free handle list <=100h4 bytes
    ; Flag 'EM' 2 bytes
    ; EMS free handle counter 2 bytes
    ; EMS free handle list <=1024 bytes
    ; EMS handle 1 word
    ; Number of pages 1 word
    ; Flag '--' 1 word
    ; Equipment List 1 word
    ; CRT 40:49h-66h 1dh bytes
    ; 40:A8h 1 dword
    ; BIOS User Data Area 40:F0--FF 10h bytes
    ; **
    ;
    main: jmp main0
    Print Macro Str
    Lea dx, Str
    call DisplayStr
    endm
    InstMsg db 'RAMinit Version 2.12 '
    db 'Copyright (c) 1989-1994 by KingSoft Ltd. ',0dh,0ah,'$'
    Msg0 db 'Already installed !',0dh,0ah,0ah
    db 'For Help, type "RI /?". ',0dh,0ah,'$'
    Msg_0 db 0ah,'Residents a new RAMinit copy [y/n] ? $'
    Msg_2 db 'OK, RI No.'
    Msg_RI db '2'
    db ' residents successful !', 0dh,0ah,'$'
    Msg1 db 'Activate with: $'
    KeyMsg db 'Right_Shift$'
    db 'Left_Shift$ '
    KMsg1 db 'Left_Ctrl$ '
    db 'Left_Alt$ '
    db 'Right_Ctrl$ '
    db 'Right_Alt$ '
    KMsg2 db 'Ctrl$ '
    db 'Alt$ '
    db 'Ctrl$ '
    db 'Alt$ '
    PlusMsg db ' + $'
    crlf db 0dh,0ah,'$'
    HelpMsg db 'Programmed by Mr. Leijun Dec 1992', 0dh,0ah,0ah
    db 'Usage: RI [options]',0dh,0ah,0ah
    db '/H,/? Display this screen',0dh,0ah
    db '/CLS Removes all TSR programs after current RI',0dh,0ah
    db '/RET Removes TSR programs include current RI',0dh,0ah
    db '/NEW Residents a new data copy of current environment',0dh,0ah
    db '/ALL Removes all RI copies and all other tsr programs',0dh,0ah
    db '/Sxyy.. Define Hotkey x=AuxHotkey yy..=shift status',0dh,0ah
    db ' x=auxiliary hotkey (default is "X") ',0dh,0ah
    db ' x equ "1" means need AuxHotkey',0dh,0ah
    db ' yy..=shift status [CAScas]',0dh,0ah
    db ' C: Left Ctrl A: Left Alt S: Left Shift',0dh,0ah
    db ' c: Right Ctrl a: Right Alt s: Right Shift',0dh,0ah,0ah
    db 'Example: "RI /S1c" means Hotkey is Right_Ctrl+X',0dh,0ah
    db ' "RI /S0Cc" means HotKey is Left_Ctrl+Right_Ctrl',0dh,0ah
    db ' "RI /CLS" equals simply press hotkey',0dh,0ah
    db ' "RI /RET" Removes all TSRs after current RI and this RI',0dh,0ah
    db 0ah
    db 'Contact me for RAMinit problems: (01)2561155 Call 1997',0dh,0ah
    db '$'
    ErrMsg db 'ERROR: Invalid options !',0dh,0ah,0ah,'$'
    WinErr db 7, 'Sorry, I cannot work in Windows DOS environment.',0dh,0ah,'$'
    SetMsg db 7, 'Defines new Hotkey successful !',0dh,0ah,0ah,'$'
    tsrOK db False
    Main0:
    cld
    Print instMsg
    call IsWinDos
    or ax, ax
    jz @@1
    Print WinErr
    mov ax, 4c00h
    int 21h
    @@1:
    call HotKeyValid
    mov cs:Status, 0
    call EMS_test
    call CmpDosVer
    call CmpSideKick
    call GetMachineID
    call ModifyHotKeyPrompt
    mov ax, 0c0d7h
    int 2fh
    mov es, ax
    cmp word ptr es:[101h], 'IE' ; 'LEI'
    jnz @@0
    mov cs:Self, ax
    @@0:
    call CmdLine
    call PrintHotKeyPrompt
    cmp cs:tsrOK, true
    jz @@2
    call tsrReplyOK
    @@2: cmp cs:tsrOK, true
    jnz @@_2
    call PrintCopies
    @@_2:
    mov word ptr cs:[100h], 'EL'
    mov byte ptr cs:[102h], 'I'
    push cs
    pop es
    push cs
    pop ds
    std
    mov si, offset eof
    mov cx, eof - offset Here
    mov di, tsrLen
    add di, cx
    inc cx
    rep movsb
    cld
    mov bx, tsrLen
    jmp bx
    Here:
    mov ax,cs
    mov es,ax
    mov di,offset endTSR
    mov cs:DataBegin, di
    mov cs:NextDataSeg, -1
    mov ax, 'XX'
    stosw
    in al, 0a1h
    mov ah, al
    in al, 21h
    push ax
    mov word ptr cs:old_8259, ax
    xor ax, ax
    out 21h,al ; CLI
    call SaveOthers
    call SetSelfInt
    call BackupVecList
    cmp cs:Power, true
    jnz @@20
    call BackupCVTchain
    call BackupMemoryManager
    @@20:
    call BackupBiosData
    sti
    mov cs:Flag, ' ' ; no busy
    mov cs:StopFlag, 0 ;
    mov cs:tsrLength, di
    call SetDosEnvSeg
    cmp cs:Self, 0
    jz @@29
    push cs
    pop ds
    push cs
    pop es
    cld
    mov cx, cs:tsrLength
    mov si, cs:DataBegin
    sub cx, si
    mov di, 120h
    mov cs:DataBegin, di
    rep movsb
    mov cs:tsrLength, di
    @@29:
    pop ax
    out 21h, al ; STI
    mov al, ah
    out 0a1h, al
    mov dx, cs:tsrLength
    inc dx
    int 27h
    ; ----------------------------------------------------------------------------
    SetDosEnvSeg:
    push ds
    push es
    mov ax, cs
    @@10: mov es, ax
    mov ax, es:[16h] ; Get father process psp segment
    or ax, ax
    jz @@11
    mov bx, es
    cmp ax, bx
    jnz @@10
    @@11:
    mov es, word ptr es:[2ch] ; Get father process env segment
    mov cs:DosEnv, es
    pop es
    pop ds
    ret
    ; ----------------------------------------------------------------------------
    SaveOthers:
    mov ax, cs:[2ch] ; Env Seg
    stosw
    call backupMCB ; Current MCB
    mov ax, 40h ; COM LPT Port
    mov ds, ax
    mov si, 0h
    mov cx, 8
    rep movsw
    mov si, 17h ; LED status
    lodsb
    stosb
    ; call OpenLEDs
    ret
    ; --------------------------------------------------------------------------
    backupMCB:
    mov ax, 'ZM'
    stosw
    push ds
    push es
    mov ah, 52h
    int 21h ; Get MCB chain head
    mov ax, es:[bx-2]
    pop es
    @@0: mov ds, ax
    cmp byte ptr ds:[0], 'Z' ; End ?
    jz @@20 cmp byte ptr ds:[0], 'M' ; Memory control block
    jnz @@30 cmp word ptr ds:[3], 0 ; Nul mcb
    jz @@10 cmp word ptr ds:[1], 0 ; Free MCB
    jnz @@10
    call SaveFreeMCB
    @@10: inc ax
    add ax, ds:[3]
    jmp @@0
    @@20:
    call SaveFreeMCB
    cmp ax, 0a000h
    inc ax
    jnb @@30
    mov ax, 9fffh ; MS-DOS UMB
    jmp @@0
    @@30:
    cmp ax, 0c000h ; 386MAX
    ja @@90
    mov ax, 0c020h
    jmp @@0
    @@90: ; Error ?
    pop ds
    mov ax, 'MM' ; Set MCB flag
    stosw
    ret
    SaveFreeMCB:
    stosw
    xor si,si
    movsb
    movsw
    movsw
    ret
    ;
    ; push ax
    ; stosw
    ; xor si,si
    ; movsb
    ; movsw
    ; movsw
    ; pop ax
    ; cmp ax, 09fffh
    ; jnb @@3
    ; push ax
    ; push ds
    ; mov ds,ax
    ; cmp byte ptr ds:[0], 'M'
    ; pop ds
    ; pop ax
    ; jnz @@4
    ; mov ax, 09fffh ; MS-DOS UMB
    ; jmp @@0
    ; @@4: cmp ax, 0c000h
    ; ja @@3
    ; mov ax, 0c020h ; 386MAX
    ; jmp @@0
    ;
    ; --------------------------------------------------------------------------
    OpenLEDs: push ax ; Open all LEDs
    or al, 070h
    mov ds:[17h], al
    mov ah, 1 int 16h
    mov cx, 4 ; Delay
    @@20: push cx
    xor cx, cx
    @@21: loop @@21
    pop cx
    loop @@20
    pop ax
    mov ds:[17h], al
    mov ah, 1 int 16h
    ret
    ; --------------------------------------------------------------------------
    SetSelfInt:
    push es
    push di
    cmp cs:self, 0
    jnz @@1
    push cs
    pop ds
    mov ax,3509h
    int 21h
    mov word ptr cs:oldInt9_addr,bx
    mov word ptr cs:oldInt9_addr[2],es
    mov dx,offset NewInt9
    mov ax,2509h
    int 21h
    mov ax,352Fh
    int 21h
    mov word ptr cs:oldInt2F_addr,bx
    mov word ptr cs:oldInt2F_addr[2],es
    mov dx,offset newInt2F
    mov ax,252Fh
    int 21h
    mov ax,351Ch
    int 21h
    mov word ptr cs:oldInt1C_addr,bx
    mov word ptr cs:oldInt1C_addr[2],es
    mov dx,offset newInt1C
    mov ax,251ch
    int 21h
    cli
    jmp @@2
    @@1:
    mov es, cs:Self
    inc es:Copies
    @@_0: cmp es:NextDataSeg, -1
    jz @@_1
    mov es, es:NextDataSeg
    jmp @@_0
    @@_1: mov es:NextDataSeg, cs
    @@2:
    pop di
    pop es
    ret
    ; -----------------------------------------------------------------------
    SaveCounter:
    mov word ptr es:[di], 'EL'
    mov byte ptr es:[di+2], 'I'
    mov byte ptr es:[di+3], bl
    xor bx, bx
    add di, 4
    ret
    ; -----------------------------------------------------------------------
    DisplayStr: push cs
    pop ds
    mov ah, 9 int 21h
    ret
    ; -----------------------------------------------------------------------
    CmdLine:
    push cs
    pop ds
    xor ax, ax
    mov si, 80h
    lodsb
    or al, al
    jnz @@1
    ret
    @@1:
    mov cx, ax
    dec ax
    push ax
    push si
    @@0: lodsb
    cmp al, ' '
    jz @@0 cmp al, '/'
    jnz @@2
    lodsb
    cmp al, 'S'
    jz @@_2
    cmp al, 's'
    jnz @@2
    @@_2:
    call SetHotKey
    Print SetMsg
    mov ax, 4c00h
    int 21h
    @@2:
    pop si
    pop ax
    push ax
    push si
    @@_3: lodsb
    cmp al, 'A'
    jb @@3 cmp al, 'Z'
    ja @@3
    add byte ptr ds:[si-1],20h ; DownCase
    @@3: loop @@_3
    pop si
    pop cx
    add si, cx
    lodsb
    cmp al, 's' ; CLS
    jnz @@5 cmp word ptr ds:[si-3], 'lc'
    jnz @@5 cmp cs:Self, 0
    jz @Err
    mov ax, 0c0d7h+1 int 2fh
    @@5: cmp al, 'h' ; HELP
    jz @help
    cmp al, '?'
    jz @help
    cmp al, 't' ; RET
    jnz @@6 cmp word ptr ds:[si-3], 'er'
    jnz @@6
    @@7:
    cmp cs:Self, 0
    jz @Err
    mov ax, 0c0d7h+2 int 2fh
    @@6: cmp al, 'w' ; NEW
    jnz @@8 cmp word ptr ds:[si-3], 'en'
    jnz @@8
    mov cs:tsrOK, true
    ret
    @@8:
    cmp al, 'l' ; ALL
    jnz @@9 cmp word ptr ds:[si-3], 'la'
    jnz @@9
    mov ax, 0c0d7h+3 int 2fh
    @@9:
    cmp al, ' '
    jnz @Err
    ret
    @Err:
    Print ErrMsg
    @help:
    Print HelpMsg
    mov ax, 4c00h
    int 21h
    ;---------------------------------------------------------------------------
    tsrReplyOK:
    cmp cs:Self, 0
    jz @@1
    Print Msg0
    push es
    mov ax, cs:Self
    @@_10: mov es, ax
    mov ax, es:NextDataSeg
    cmp ax, -1
    jnz @@_10
    mov ax, es
    @@_0: push ax
    dec ax
    mov es, ax
    mov bx, es:[3]
    pop ax
    add ax, bx
    inc ax
    mov es, ax
    cmp word ptr es:[0], 'OC'
    jz @@_0
    mov bx, cs
    cmp ax, bx
    pop es
    jz @@2
    Print Msg_0
    mov ah, 1 int 21h
    push ax
    Print crlf
    pop ax
    cmp al, 'y'
    jz @@3 cmp al, 'Y'
    jz @@3
    @@2: ; Print Msg_1
    mov ax, 4c01h
    int 21h
    @@3:
    @@1: mov cs:tsrOK, true
    ret
    PrintCopies:
    cmp cs:Self, 0
    jz @@1
    push es ; Added -by- Mr. Lei
    mov es, cs:Self ; Aug 24, 1993
    mov al, es:Copies
    inc al ; Total RI copies
    push ax ; Set es = current mcb
    mov ax, cs
    dec ax
    mov es, ax
    pop ax
    mov cx, 5 ; Search end of file name
    mov bx, 8
    @@10: inc bx
    cmp byte ptr es:[bx], 20h
    jz @@20 cmp byte ptr es:[bx], 0ffh
    jz @@20 cmp byte ptr es:[bx], 00h
    jz @@20
    loop @@10
    @@20: ; Set current RI no
    mov byte ptr es:[bx], ':' ; "RI:2"
    mov byte ptr es:[bx+1], al
    cmp bx, 8+7
    jnb @@30
    mov byte ptr es:[bx+2], 0
    @@30:
    pop es
    mov cs:Msg_RI, al
    Print Msg_2
    @@1: ret
    ;---------------------------------------------------------------------------
    ; Backup Interrupt Vector List
    ;
    BackupVecList:
    push ds
    push cs
    pop es
    xor si,si ; Vectors
    mov ds,si
    movsw
    movsw
    xor bx, bx
    mov cx,00ffh
    @@0: lodsw
    xchg dx, ax
    lodsw
    cmp ax, es:[di-2]
    jnz @@1 cmp dx, es:[di-4]
    jz @@2
    @@1: or bx, bx
    jz @@3
    call SaveCounter
    @@3: xchg dx, ax
    stosw
    xchg dx, ax
    stosw
    loop @@0
    jmp @@4
    @@2: inc bx
    loop @@0
    call SaveCounter
    @@4:
    pop ds
    ret
    ;
    ;-----------------------------------------------------------------------------
    BackupCVTchain:
    mov ax, 'VC'
    stosw
    push ax
    push bx
    push cx
    push ds
    push es
    mov ah, 52h
    int 21h ; ES:BX -- DOS table as described below
    ; --------------------------------------------------------------------
    push es ; DPB chains
    push bx
    lds si, es:[bx]
    push cs
    pop es
    mov ax, si
    stosw
    mov ax, ds
    stosw
    mov bx, cs:cvtOfs
    xor cx, cx
    @@1: mov al, ds:[si+1]
    stosb
    mov ax, ds:[si+bx+12h]
    stosw
    mov ax, ds:[si+bx+14h]
    stosw
    inc cx
    lds si, ds:[si+bx+18h]
    cmp si, -1
    jnz @@1
    ; mov ax, 5
    ; mul cl
    ; add ax, 4
    ; add cs:tsrLength, ax
    pop bx
    pop es
    ; --------------------------------------------------------------------
    push es ; DCB file control blocks
    push bx
    les bx, es:[bx+4]
    @@11: cmp word ptr es:[bx], -1
    jz @@10
    les bx, es:[bx]
    jmp @@11
    @@10:
    mov ax, es
    xchg ax, bx
    push cs
    pop es
    stosw
    xchg ax, bx
    stosw
    pop bx
    pop es
    ; add cs:tsrLength, 4
    ; ---------------------------------------------------------------------
    push es ; Device Driver Chains
    pop ds
    add bx, 22h
    mov si, bx ; NUL
    pop es
    mov ax, si
    stosw
    mov ax, ds
    stosw
    xor cx, cx
    xor bx, bx
    @@9: push si
    mov cl, 5
    rep movsw
    inc bx
    pop si
    lds si, ds:[si]
    mov ax, si
    inc ax
    jnz @@9
    pop ds
    pop cx
    pop bx
    pop ax
    ret
    ; ----------------------------------------------------------------------------
    BackupBiosData:
    mov ax, '--'
    stosw
    push ds
    push si
    mov si, 40h
    mov ds, si
    mov si, 10h
    movsw
    mov si, 0a8h
    movsw
    movsw
    mov si, 49h
    mov cx, 1dh
    rep movsb
    mov si, 0f0h
    mov cx, 8
    rep movsw
    pop si
    pop ds
    ret
    ; ---------------------------------------------------------------------------
    BackupMemoryManager:
    push cs
    pop es
    push ds
    push es
    call SaveXMSstatus
    call SaveEMSstatus
    pop es
    pop ds
    ret
    ;---------------------------------------------------------------------
    SaveEMSstatus:
    test cs:status, EMSbit
    jnz @@1
    ret
    @@1:
    mov ax, 'ME'
    stosw
    inc di
    inc di
    push di
    mov ah, 4dh
    int 67h
    pop di
    mov es:[di-2], bx
    shl bx, 1
    shl bx, 1
    add di, bx
    ret
    ; -------------------------------------------------------------------
    SaveXMSstatus:
    call XMS_test
    test cs:status, XMSbit
    jnz @@1
    ret
    @@1:
    mov ax, 'MX'
    stosw
    mov dx, 1
    call XMS_alloc
    jnz @@_1
    xor cx, cx ; XMS alloc failure
    stosw
    ret
    @@_1:
    push dx
    sub dx, MaxHandles  10
    @@2:
    push dx
    call XMS_Lock
    pop dx
    jnz @@3 cmp bl, 0a2h
    jnz @@4
    add dx, 10
    jmp @@2
    @@3: push dx
    call XMS_unlock
    pop dx
    @@4:
    mov cs:handle_begin, dx
    pop dx
    push dx
    call XMS_bstat
    xor cx, cx
    mov cl, bl
    inc cx
    pop dx
    call XMS_Free
    mov dx, cs:Handle_begin
    push cx
    push cs
    pop es
    mov ax, cx
    stosw
    @@5: push dx
    call XMS_Lock
    pop dx
    jnz @@6 cmp bl, 0a2h ; Handle invalid
    jz @@7
    @@6: call XMS_unlock
    add dx, 10
    jmp @@5
    @@7: mov ax, dx
    stosw
    add dx, 10
    loop @@5
    pop cx
    ret
    ; ------------------------------------------------------------------
    XMS_test:
    push es
    mov ax, 4300h
    int 2fh
    cmp al, 80h
    jnz @@9
    mov ax, 4310h
    int 2fh
    mov cs:XMS_control, bx
    mov cs:XMS_control[2], es
    or cs:Status, XMSbit
    @@9:
    pop es
    ret
    XMS_stat:
    mov ah, 0
    call dword ptr cs:xms_control
    mov hma_exist, dl
    ret
    hma_exist db 0
    XMS_alloc:
    mov ah, 9
    call dword ptr cs:xms_control
    or ax, ax
    ret
    XMS_lock:
    mov ah, 0ch
    call dword ptr cs:xms_control
    or ax, ax
    ret
    XMS_unlock:
    mov ah, 0dh
    call dword ptr cs:xms_control
    or ax, ax
    ret
    XMS_bstat:
    mov ah, 0eh
    call dword ptr cs:xms_control
    or ax, ax
    ret
    XMS_free:
    mov ah, 0ah
    call dword ptr cs:xms_control
    or ax, ax
    ret
    ; ----------------------------------------------------------------------------
    EMS_test:
    push cs
    pop ds
    mov dx, offset EMMname
    mov ax, 3d00h
    int 21h
    jc @@2
    mov bx, ax
    mov ah, 3eh
    int 21h
    or cs:Status, EMSbit
    @@2:
    ret
    EMMname db 'EMMXXXX0',0
    ; -----------------------------------------------------------------------------
    SetHotKey:
    xor bx, bx
    lodsb
    push ax
    @@1: lodsb
    cmp al, 0dh
    jz @@9 cmp al, 'C'
    jnz @@2
    or bl, LeftCtrl
    jmp @@1
    @@2:
    cmp al, 'c'
    jnz @@3
    or bl, RightCtrl
    jmp @@1
    @@3:
    cmp al, 'A'
    jnz @@4
    or bl, LeftAlt
    jmp @@1
    @@4:
    cmp al, 'a'
    jnz @@5
    or bl, RightAlt
    jmp @@1
    @@5:
    cmp al, 'S'
    jnz @@6
    or bl, LeftShift
    jmp @@1
    @@6:
    cmp al, 's'
    jnz @@7
    or bl, RightShift
    jmp @@1
    @@7: pop ax
    jmp @Err
    @@9:
    mov cs:HotKey, bl
    pop ax
    mov cs:AuxHotKey, 2dh ; 'X' scan key
    cmp al, '1'
    jz @@29
    mov cs:AuxHotKey, 0
    @@29:
    cmp cs:Self, 0
    jz @@30
    push es
    mov es, cs:Self
    mov es:HotKey, bl
    mov bl, cs:AuxHotKey
    mov es:AuxHotKey, bl
    pop es
    @@30:
    call GetRunFileName
    mov ax, 3d02h
    int 21h
    jc @@10
    push cs
    pop ds
    mov bx, ax
    mov cx, 4
    mov dx, 100h
    mov ah, 40h
    int 21h
    jc @@10
    mov ax, 4200h
    xor cx, cx
    mov dx, 17h
    int 21h
    jc @@10
    mov cx, 1
    mov dx, offset AuxHotKey
    mov ah, 40h
    int 21h
    jc @@10
    mov ah, 3eh
    int 21h
    @@10:
    ret
    ; -----------------------------------------------------------------------
    GetRunFileName:
    ; Return:
    ; DS:DX Pointer of this run file name ASCIIZ string
    push ax
    push bx
    push cx
    push si
    push di
    push es
    push cs
    pop es
    mov ax, es:[2ch]
    mov es, ax
    xor di, di
    mov cx, 1000h
    xor al, al
    @@1: repnz scasb
    cmp es:[di], al
    loopnz @@1
    mov dx, di
    add dx, 3
    push es
    pop ds
    pop es
    pop di
    pop si
    pop cx
    pop bx
    pop ax
    ret
    ; ---------------------------------------------------------------------------
    GetMachineID:
    push es
    mov KBD102,True
    mov ax,40h
    mov es,ax
    test byte ptr es:[96h], 00010000b
    jnz @@1
    mov Kbd102,False
    @@1:
    xor ax,ax
    dec ax
    mov es,ax
    mov al,es:[0eh]
    mov cs:MachineID, al
    pop es
    ret
    ; ---------------------------------------------------------------------------
    ModifyHotKeyPrompt:
    cmp cs:Kbd102, True
    jz @@9
    push cs
    pop es
    push cs
    pop ds
    mov cx, 124
    mov si, offset KMsg2
    mov di, offset KMsg1
    rep movsb
    @@9: cmp cs:MachineID, 0fch
    jna @@10
    mov cs:clsStrcolor, 70h ; Mono
    mov cs:clsStr, 70h
    @@10:
    ret
    ; ---------------------------------------------------------------------------
    PrintHotKeyPrompt:
    Print Msg1
    mov al, cs:HotKey
    mov ah, al
    shr al, 1
    shr al, 1
    and ax, 33ch
    or al, ah
    mov dx, offset KeyMsg
    @@40:
    or ax, ax ; Mr. Lei 4/25/1993
    jz @@_42
    shr al, 1
    push ax
    jnc @@41
    push ax
    call ColorDisplayStr
    ; mov ah, 9
    ; int 21h
    pop ax
    or al, al
    jz @@42
    push dx
    mov dx, offset PlusMsg
    call ColorDisplayStr
    ; Print PlusMsg
    pop dx
    @@41: add dx, 12
    pop ax
    jmp @@40
    @@42: pop ax
    @@_42: cmp cs:AuxHotKey, 0
    jz @@43 cmp cs:HotKey, 0 ; Mr. Lei
    jz @@_43
    mov dx, offset PlusMsg
    call ColorDisplayStr
    ; Print PlusMsg
    @@_43: mov dx, offset AuxHotKeyName
    call ColorDisplayStr
    ; Print AuxHotKeyName
    @@43:
    Print crlf
    ret
    ColorDisplayStr:
    push bx
    push cx
    push dx
    push si
    mov bl, 0fh
    mov si, dx
    xor bh, bh
    mov cx, 1
    @@1: lodsb
    cmp al, '$'
    jz @@2
    or al, al
    jz @@2
    push cx
    mov ah, 09h
    int 10h
    mov ah, 3 int 10h
    inc dl
    mov ah, 2 int 10h
    pop cx
    jmp short @@1
    @@2:
    pop si
    pop dx
    pop cx
    pop bx
    ret
    ; ---------------------------------------------------------------------------
    CmpSideKick:
    xor ax, ax
    mov es, ax
    les bx, es:[20h]
    cmp word ptr es:[bx-4], 4b53h
    jnz @@1 cmp word ptr es:[bx-2], 4942h
    jz @@2
    @@1: mov es, ax
    les bx, es:[94h]
    cmp word ptr es:[bx-2], 4b53h
    jz @@2
    ret
    @@2: or cs:Status, SKbit
    ret
    ; ---------------------------------------------------------------------------
    CmpDosVer: mov ah, 30h
    int 21h
    cmp al, 3
    jb @@1 cmp al, 3
    jna @@2
    mov cs:cvtOfs, 1
    ret
    @@2: mov cs:cvtOfs, 0
    ret
    @@1: Print DosVerErr
    mov ax, 4cffh
    int 21h
    DosVerErr db 'Sorry, DOS version too lower !',0dh,0ah,'$'
    HotKeyValid:
    cmp cs:HotKey, 0
    jnz @@_1
    cmp cs:AuxHotKey, 0
    jnz @@_1
    Print HotKeyErr
    mov ax, 4cfeh
    int 21h
    @@_1: ret
    HotKeyErr db 'Sorry, please setup hotkey again. ',0dh,0ah,'$'
    eof:
    ends
    end Start
    ; ------------- The End ! ---------------------------------------------------
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648
    • 649
    • 650
    • 651
    • 652
    • 653
    • 654
    • 655
    • 656
    • 657
    • 658
    • 659
    • 660
    • 661
    • 662
    • 663
    • 664
    • 665
    • 666
    • 667
    • 668
    • 669
    • 670
    • 671
    • 672
    • 673
    • 674
    • 675
    • 676
    • 677
    • 678
    • 679
    • 680
    • 681
    • 682
    • 683
    • 684
    • 685
    • 686
    • 687
    • 688
    • 689
    • 690
    • 691
    • 692
    • 693
    • 694
    • 695
    • 696
    • 697
    • 698
    • 699
    • 700
    • 701
    • 702
    • 703
    • 704
    • 705
    • 706
    • 707
    • 708
    • 709
    • 710
    • 711
    • 712
    • 713
    • 714
    • 715
    • 716
    • 717
    • 718
    • 719
    • 720
    • 721
    • 722
    • 723
    • 724
    • 725
    • 726
    • 727
    • 728
    • 729
    • 730
    • 731
    • 732
    • 733
    • 734
    • 735
    • 736
    • 737
    • 738
    • 739
    • 740
    • 741
    • 742
    • 743
    • 744
    • 745
    • 746
    • 747
    • 748
    • 749
    • 750
    • 751
    • 752
    • 753
    • 754
    • 755
    • 756
    • 757
    • 758
    • 759
    • 760
    • 761
    • 762
    • 763
    • 764
    • 765
    • 766
    • 767
    • 768
    • 769
    • 770
    • 771
    • 772
    • 773
    • 774
    • 775
    • 776
    • 777
    • 778
    • 779
    • 780
    • 781
    • 782
    • 783
    • 784
    • 785
    • 786
    • 787
    • 788
    • 789
    • 790
    • 791
    • 792
    • 793
    • 794
    • 795
    • 796
    • 797
    • 798
    • 799
    • 800
    • 801
    • 802
    • 803
    • 804
    • 805
    • 806
    • 807
    • 808
    • 809
    • 810
    • 811
    • 812
    • 813
    • 814
    • 815
    • 816
    • 817
    • 818
    • 819
    • 820
    • 821
    • 822
    • 823
    • 824
    • 825
    • 826
    • 827
    • 828
    • 829
    • 830
    • 831
    • 832
    • 833
    • 834
    • 835
    • 836
    • 837
    • 838
    • 839
    • 840
    • 841
    • 842
    • 843
    • 844
    • 845
    • 846
    • 847
    • 848
    • 849
    • 850
    • 851
    • 852
    • 853
    • 854
    • 855
    • 856
    • 857
    • 858
    • 859
    • 860
    • 861
    • 862
    • 863
    • 864
    • 865
    • 866
    • 867
    • 868
    • 869
    • 870
    • 871
    • 872
    • 873
    • 874
    • 875
    • 876
    • 877
    • 878
    • 879
    • 880
    • 881
    • 882
    • 883
    • 884
    • 885
    • 886
    • 887
    • 888
    • 889
    • 890
    • 891
    • 892
    • 893
    • 894
    • 895
    • 896
    • 897
    • 898
    • 899
    • 900
    • 901
    • 902
    • 903
    • 904
    • 905
    • 906
    • 907
    • 908
    • 909
    • 910
    • 911
    • 912
    • 913
    • 914
    • 915
    • 916
    • 917
    • 918
    • 919
    • 920
    • 921
    • 922
    • 923
    • 924
    • 925
    • 926
    • 927
    • 928
    • 929
    • 930
    • 931
    • 932
    • 933
    • 934
    • 935
    • 936
    • 937
    • 938
    • 939
    • 940
    • 941
    • 942
    • 943
    • 944
    • 945
    • 946
    • 947
    • 948
    • 949
    • 950
    • 951
    • 952
    • 953
    • 954
    • 955
    • 956
    • 957
    • 958
    • 959
    • 960
    • 961
    • 962
    • 963
    • 964
    • 965
    • 966
    • 967
    • 968
    • 969
    • 970
    • 971
    • 972
    • 973
    • 974
    • 975
    • 976
    • 977
    • 978
    • 979
    • 980
    • 981
    • 982
    • 983
    • 984
    • 985
    • 986
    • 987
    • 988
    • 989
    • 990
    • 991
    • 992
    • 993
    • 994
    • 995
    • 996
    • 997
    • 998
    • 999
    • 1000
    • 1001
    • 1002
    • 1003
    • 1004
    • 1005
    • 1006
    • 1007
    • 1008
    • 1009
    • 1010
    • 1011
    • 1012
    • 1013
    • 1014
    • 1015
    • 1016
    • 1017
    • 1018
    • 1019
    • 1020
    • 1021
    • 1022
    • 1023
    • 1024
    • 1025
    • 1026
    • 1027
    • 1028
    • 1029
    • 1030
    • 1031
    • 1032
    • 1033
    • 1034
    • 1035
    • 1036
    • 1037
    • 1038
    • 1039
    • 1040
    • 1041
    • 1042
    • 1043
    • 1044
    • 1045
    • 1046
    • 1047
    • 1048
    • 1049
    • 1050
    • 1051
    • 1052
    • 1053
    • 1054
    • 1055
    • 1056
    • 1057
    • 1058
    • 1059
    • 1060
    • 1061
    • 1062
    • 1063
    • 1064
    • 1065
    • 1066
    • 1067
    • 1068
    • 1069
    • 1070
    • 1071
    • 1072
    • 1073
    • 1074
    • 1075
    • 1076
    • 1077
    • 1078
    • 1079
    • 1080
    • 1081
    • 1082
    • 1083
    • 1084
    • 1085
    • 1086
    • 1087
    • 1088
    • 1089
    • 1090
    • 1091
    • 1092
    • 1093
    • 1094
    • 1095
    • 1096
    • 1097
    • 1098
    • 1099
    • 1100
    • 1101
    • 1102
    • 1103
    • 1104
    • 1105
    • 1106
    • 1107
    • 1108
    • 1109
    • 1110
    • 1111
    • 1112
    • 1113
    • 1114
    • 1115
    • 1116
    • 1117
    • 1118
    • 1119
    • 1120
    • 1121
    • 1122
    • 1123
    • 1124
    • 1125
    • 1126
    • 1127
    • 1128
    • 1129
    • 1130
    • 1131
    • 1132
    • 1133
    • 1134
    • 1135
    • 1136
    • 1137
    • 1138
    • 1139
    • 1140
    • 1141
    • 1142
    • 1143
    • 1144
    • 1145
    • 1146
    • 1147
    • 1148
    • 1149
    • 1150
    • 1151
    • 1152
    • 1153
    • 1154
    • 1155
    • 1156
    • 1157
    • 1158
    • 1159
    • 1160
    • 1161
    • 1162
    • 1163
    • 1164
    • 1165
    • 1166
    • 1167
    • 1168
    • 1169
    • 1170
    • 1171
    • 1172
    • 1173
    • 1174
    • 1175
    • 1176
    • 1177
    • 1178
    • 1179
    • 1180
    • 1181
    • 1182
    • 1183
    • 1184
    • 1185
    • 1186
    • 1187
    • 1188
    • 1189
    • 1190
    • 1191
    • 1192
    • 1193
    • 1194
    • 1195
    • 1196
    • 1197
    • 1198
    • 1199
    • 1200
    • 1201
    • 1202
    • 1203
    • 1204
    • 1205
    • 1206
    • 1207
    • 1208
    • 1209
    • 1210
    • 1211
    • 1212
    • 1213
    • 1214
    • 1215
    • 1216
    • 1217
    • 1218
    • 1219
    • 1220
    • 1221
    • 1222
    • 1223
    • 1224
    • 1225
    • 1226
    • 1227
    • 1228
    • 1229
    • 1230
    • 1231
    • 1232
    • 1233
    • 1234
    • 1235
    • 1236
    • 1237
    • 1238
    • 1239
    • 1240
    • 1241
    • 1242
    • 1243
    • 1244
    • 1245
    • 1246
    • 1247
    • 1248
    • 1249
    • 1250
    • 1251
    • 1252
    • 1253
    • 1254
    • 1255
    • 1256
    • 1257
    • 1258
    • 1259
    • 1260
    • 1261
    • 1262
    • 1263
    • 1264
    • 1265
    • 1266
    • 1267
    • 1268
    • 1269
    • 1270
    • 1271
    • 1272
    • 1273
    • 1274
    • 1275
    • 1276
    • 1277
    • 1278
    • 1279
    • 1280
    • 1281
    • 1282
    • 1283
    • 1284
    • 1285
    • 1286
    • 1287
    • 1288
    • 1289
    • 1290
    • 1291
    • 1292
    • 1293
    • 1294
    • 1295
    • 1296
    • 1297
    • 1298
    • 1299
    • 1300
    • 1301
    • 1302
    • 1303
    • 1304
    • 1305
    • 1306
    • 1307
    • 1308
    • 1309
    • 1310
    • 1311
    • 1312
    • 1313
    • 1314
    • 1315
    • 1316
    • 1317
    • 1318
    • 1319
    • 1320
    • 1321
    • 1322
    • 1323
    • 1324
    • 1325
    • 1326
    • 1327
    • 1328
    • 1329
    • 1330
    • 1331
    • 1332
    • 1333
    • 1334
    • 1335
    • 1336
    • 1337
    • 1338
    • 1339
    • 1340
    • 1341
    • 1342
    • 1343
    • 1344
    • 1345
    • 1346
    • 1347
    • 1348
    • 1349
    • 1350
    • 1351
    • 1352
    • 1353
    • 1354
    • 1355
    • 1356
    • 1357
    • 1358
    • 1359
    • 1360
    • 1361
    • 1362
    • 1363
    • 1364
    • 1365
    • 1366
    • 1367
    • 1368
    • 1369
    • 1370
    • 1371
    • 1372
    • 1373
    • 1374
    • 1375
    • 1376
    • 1377
    • 1378
    • 1379
    • 1380
    • 1381
    • 1382
    • 1383
    • 1384
    • 1385
    • 1386
    • 1387
    • 1388
    • 1389
    • 1390
    • 1391
    • 1392
    • 1393
    • 1394
    • 1395
    • 1396
    • 1397
    • 1398
    • 1399
    • 1400
    • 1401
    • 1402
    • 1403
    • 1404
    • 1405
    • 1406
    • 1407
    • 1408
    • 1409
    • 1410
    • 1411
    • 1412
    • 1413
    • 1414
    • 1415
    • 1416
    • 1417
    • 1418
    • 1419
    • 1420
    • 1421
    • 1422
    • 1423
    • 1424
    • 1425
    • 1426
    • 1427
    • 1428
    • 1429
    • 1430
    • 1431
    • 1432
    • 1433
    • 1434
    • 1435
    • 1436
    • 1437
    • 1438
    • 1439
    • 1440
    • 1441
    • 1442
    • 1443
    • 1444
    • 1445
    • 1446
    • 1447
    • 1448
    • 1449
    • 1450
    • 1451
    • 1452
    • 1453
    • 1454
    • 1455
    • 1456
    • 1457
    • 1458
    • 1459
    • 1460
    • 1461
    • 1462
    • 1463
    • 1464
    • 1465
    • 1466
    • 1467
    • 1468
    • 1469
    • 1470
    • 1471
    • 1472
    • 1473
    • 1474
    • 1475
    • 1476
    • 1477
    • 1478
    • 1479
    • 1480
    • 1481
    • 1482
    • 1483
    • 1484
    • 1485
    • 1486
    • 1487
    • 1488
    • 1489
    • 1490
    • 1491
    • 1492
    • 1493
    • 1494
    • 1495
    • 1496
    • 1497
    • 1498
    • 1499
    • 1500
    • 1501
    • 1502
    • 1503
    • 1504
    • 1505
    • 1506
    • 1507
    • 1508
    • 1509
    • 1510
    • 1511
    • 1512
    • 1513
    • 1514
    • 1515
    • 1516
    • 1517
    • 1518
    • 1519
    • 1520
    • 1521
    • 1522
    • 1523
    • 1524
    • 1525
    • 1526
    • 1527
    • 1528
    • 1529
    • 1530
    • 1531
    • 1532
    • 1533
    • 1534
    • 1535
    • 1536
    • 1537
    • 1538
    • 1539
    • 1540
    • 1541
    • 1542
    • 1543
    • 1544
    • 1545
    • 1546
    • 1547
    • 1548
    • 1549
    • 1550
    • 1551
    • 1552
    • 1553
    • 1554
    • 1555
    • 1556
    • 1557
    • 1558
    • 1559
    • 1560
    • 1561
    • 1562
    • 1563
    • 1564
    • 1565
    • 1566
    • 1567
    • 1568
    • 1569
    • 1570
    • 1571
    • 1572
    • 1573
    • 1574
    • 1575
    • 1576
    • 1577
    • 1578
    • 1579
    • 1580
    • 1581
    • 1582
    • 1583
    • 1584
    • 1585
    • 1586
    • 1587
    • 1588
    • 1589
    • 1590
    • 1591
    • 1592
    • 1593
    • 1594
    • 1595
    • 1596
    • 1597
    • 1598
    • 1599
    • 1600
    • 1601
    • 1602
    • 1603
    • 1604
    • 1605
    • 1606
    • 1607
    • 1608
    • 1609
    • 1610
    • 1611
    • 1612
    • 1613
    • 1614
    • 1615
    • 1616
    • 1617
    • 1618
    • 1619
    • 1620
    • 1621
    • 1622
    • 1623
    • 1624
    • 1625
    • 1626
    • 1627
    • 1628
    • 1629
    • 1630
    • 1631
    • 1632
    • 1633
    • 1634
    • 1635
    • 1636
    • 1637
    • 1638
    • 1639
    • 1640
    • 1641
    • 1642
    • 1643
    • 1644
    • 1645
    • 1646
    • 1647
    • 1648
    • 1649
    • 1650
    • 1651
    • 1652
    • 1653
    • 1654
    • 1655
    • 1656
    • 1657
    • 1658
    • 1659
    • 1660
    • 1661
    • 1662
    • 1663
    • 1664
    • 1665
    • 1666
    • 1667
    • 1668
    • 1669
    • 1670
    • 1671
    • 1672
    • 1673
    • 1674
    • 1675
    • 1676
    • 1677
    • 1678
    • 1679
    • 1680
    • 1681
    • 1682
    • 1683
    • 1684
    • 1685
    • 1686
    • 1687
    • 1688
    • 1689
    • 1690
    • 1691
    • 1692
    • 1693
    • 1694
    • 1695
    • 1696
    • 1697
    • 1698
    • 1699
    • 1700
    • 1701
    • 1702
    • 1703
    • 1704
    • 1705
    • 1706
    • 1707
    • 1708
    • 1709
    • 1710
    • 1711
    • 1712
    • 1713
    • 1714
    • 1715
    • 1716
    • 1717
    • 1718
    • 1719
    • 1720
    • 1721
    • 1722
    • 1723
    • 1724
    • 1725
    • 1726
    • 1727
    • 1728
    • 1729
    • 1730
    • 1731
    • 1732
    • 1733
    • 1734
    • 1735
    • 1736
    • 1737
    • 1738
    • 1739
    • 1740
    • 1741
    • 1742
    • 1743
    • 1744
    • 1745
    • 1746
    • 1747
    • 1748
    • 1749
    • 1750
    • 1751
    • 1752
    • 1753
    • 1754
    • 1755
    • 1756
    • 1757
    • 1758
    • 1759
    • 1760
    • 1761
    • 1762
    • 1763
    • 1764
    • 1765
    • 1766
    • 1767
    • 1768
    • 1769
    • 1770
    • 1771
    • 1772
    • 1773
    • 1774
    • 1775
    • 1776
    • 1777
    • 1778
    • 1779
    • 1780
    • 1781
    • 1782
    • 1783
    • 1784
    • 1785
    • 1786
    • 1787
    • 1788
    • 1789
    • 1790
    • 1791
    • 1792
    • 1793
    • 1794
    • 1795
    • 1796
    • 1797
    • 1798
    • 1799
    • 1800
    • 1801
    • 1802
    • 1803
    • 1804
    • 1805
    • 1806
    • 1807
    • 1808
    • 1809
    • 1810
    • 1811
    • 1812
    • 1813
    • 1814
    • 1815
    • 1816
    • 1817
    • 1818
    • 1819
    • 1820
    • 1821
    • 1822
    • 1823
    • 1824
    • 1825
    • 1826
    • 1827
    • 1828
    • 1829
    • 1830
    • 1831
    • 1832
    • 1833
    • 1834
    • 1835
    • 1836
    • 1837
    • 1838
    • 1839
    • 1840
    • 1841
    • 1842
    • 1843
    • 1844
    • 1845
    • 1846
    • 1847
    • 1848
    • 1849
    • 1850
    • 1851
    • 1852
    • 1853
    • 1854
    • 1855
    • 1856
    • 1857
    • 1858
    • 1859
    • 1860
    • 1861
    • 1862
    • 1863
    • 1864
    • 1865
    • 1866
    • 1867
    • 1868
    • 1869
    • 1870
    • 1871
    • 1872
    • 1873
    • 1874
    • 1875
    • 1876
    • 1877
    • 1878
    • 1879
    • 1880
    • 1881
    • 1882
    • 1883
    • 1884
    • 1885
    • 1886
    • 1887
    • 1888
    • 1889
    • 1890
    • 1891
    • 1892
    • 1893
    • 1894
    • 1895
    • 1896
    • 1897
    • 1898
    • 1899
    • 1900
    • 1901
    • 1902
    • 1903
    • 1904
    • 1905
    • 1906
    • 1907
    • 1908
    • 1909
    • 1910
    • 1911
    • 1912
    • 1913
    • 1914
    • 1915
    • 1916
    • 1917
    • 1918
    • 1919
    • 1920
    • 1921
    • 1922
    • 1923
    • 1924
    • 1925
    • 1926
    • 1927
    • 1928
    • 1929
    • 1930
    • 1931
    • 1932
    • 1933
    • 1934
    • 1935
    • 1936
    • 1937
    • 1938
    • 1939
    • 1940
    • 1941
    • 1942
    • 1943
    • 1944
    • 1945
    • 1946
    • 1947
    • 1948
    • 1949
    • 1950
    • 1951
    • 1952
    • 1953
    • 1954
    • 1955
    • 1956
    • 1957
    • 1958
    • 1959
    • 1960
    • 1961
    • 1962
    • 1963
    • 1964
    • 1965
    • 1966
    • 1967
    • 1968
    • 1969
    • 1970
    • 1971
    • 1972
    • 1973
    • 1974
    • 1975
    • 1976
    • 1977
    • 1978
    • 1979
    • 1980
    • 1981
    • 1982
    • 1983
    • 1984
    • 1985
    • 1986
    • 1987
    • 1988
    • 1989
    • 1990
    • 1991

    总结

    本文没有深入分析大佬们的代码,只是晾晒一下,饱饱眼福吧。

  • 相关阅读:
    asp.net校园二手交易平台系统VS开发sqlserver数据库web结构c#编程计算机网页
    2023/11/7 JAVA学习(异常处理方式,collection集合,list,set)
    PyTorch使用多GPU并行训练及其原理和注意事项
    高并发使用JVM锁和MySQL锁解决数据不一致问题
    【C】想练习C语言?通讯录的实现了解一下
    福建师范大学计算机考研资料汇总
    人工智能轨道交通行业周刊-第24期(2022.11.21-11.27)
    C++成员指针
    11.17 - 每日一题 - 408
    Python常见函数
  • 原文地址:https://blog.csdn.net/jgku/article/details/128021735