summaryrefslogtreecommitdiffstats
path: root/private/mvdm/wow16/kernel31/ldutil.asm
blob: d2b5e8e1409e5ac615a8d60378dbe0e8f1fdd2ec (plain) (blame)
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
	TITLE	LDUTIL - Loader support procedures

.xlist
include kernel.inc
include newexe.inc
include tdb.inc
include protect.inc
.list

;externFP GetCurrentPDB

if ROM and PMODE32
externFP HocusROMBase
endif

DataBegin

;externB Kernel_Flags
;externW AltfEEMS
externW headTDB
externW hExeHead
;externW pGlobalHeap
;externW MyCSDS
externW topPDB
externW cur_dos_pdb
externW Win_PDB
externW curTDB
;externW segSwapArea

DataEnd

externFP CallWEP

sBegin	CODE
assumes CS,CODE
assumes DS,NOTHING
assumes ES,NOTHING

externNP MyUpper
externNP MyLock
externNP LoadNRTable
externNP LoadSegment
externNP GetOwner
externNP GetCachedFileHandle

if SDEBUG
externNP DebugFreeSegment
endif

externFP IGlobalAlloc
externFP IGlobalFree
;externFP IGlobalLock
externFP IGlobalUnfix
externFP IGlobalHandle
externFP GlobalFlags
externFP FreeNRTable
externFP Int21Handler

ifdef	DBCS			;declare it.
externNP MyIsDBCSLeadByte	;Use near one as we are in the same seg
endif

if ROM
externFP FreeSelector
externNP alloc_data_sel16
endif

cProc	SafeCall,<PUBLIC,FAR>
	parmD	Addr
cBegin
	call	Addr
cEnd

;-----------------------------------------------------------------------;
; GetExePtr								;
; 									;
; Returns the exe header pointer for the passed handle.			;
; 									;
; Arguments:								;
;	parmW   hinstance						;
; 									;
; Returns:								;
; 									;
; Error Returns:							;
;	AX = 0								;
;									;
; Registers Preserved:							;
; 									;
; Registers Destroyed:							;
; 									;
; Calls:								;
; 									;
; History:								;
; 									;
;  Mon Aug 03, 1987 04:40:45p  -by-  David N. Weise   [davidw]          ;
; Rewrote it to work with expanded memory.  Note that if the handle	;
; passed is truly bogus we could still catch a page fault under		;
; Win386.								;
;-----------------------------------------------------------------------;

	assumes	ds, nothing
	assumes	es, nothing

cProc	GetExePtr,<PUBLIC,FAR>
	parmW   hinstance
cBegin
	mov	ax,hinstance
	test	ax,GA_FIXED		; Passed a segment address?
	jz	not_module
	mov	es,ax
	cmp	es:[ne_magic],NEMAGIC	;  Yes, does it point to a Module?
	jz	gxdone

not_module:
	SetKernelDS	es
	mov	cx,headTDB
	assumes	es, nothing
find_TDB:
	jcxz	last_chance
	mov	es,cx
	cmp	ax,es:[TDB_module]
	jz	found_it
	mov	cx,es:[TDB_next]
	jmp	find_TDB
found_it:
	mov	ax,es:[TDB_pModule]
	jmps	gxdone

last_chance:				; The problem here is that USER
	cCall	MyLock,<ax>		;  KNOWS that hinstance is but
	or	ax,ax			;  the handle to his data segment.
	jz	gxdone
	mov	es,ax
	cmp	es:[ne_magic],NEMAGIC
	je	gxdone

	cCall	GetOwner,<ax>
	or	ax,ax
	jz	gxfail
	mov	es,ax
	cmp	es:[ne_magic],NEMAGIC
	je	gxdone

	; The owner,ax, is now a PDB. We gotta find the TDB
	SetKernelDS	es
	mov	cx,headTDB
	assumes	es, nothing
find_PDB:
	jcxz	gxfail
	mov	es,cx
	cmp	ax,es:[TDB_PDB]
	jz	found_PDB
	mov	cx,es:[TDB_next]
	jmp	find_PDB
found_PDB:
	mov	ax,es:[TDB_pModule]
	jmps	gxdone


gxfail:
if KDEBUG
	xor	cx,cx
	kerror	ERR_LDMODULE,<Invalid module handle>,cx,hinstance
endif
	xor	ax,ax
gxdone:	mov	cx,ax

cEnd

;-----------------------------------------------------------------------;
;									;
;  GetExpWinVer - return the expected Windows version for a given	;
;		  module handle						;
;									;
; Arguments:								;
;	parmW   hinstance						;
; 									;
; Returns:								;
;	AX = expected windows version					;
;	DX = BOOL proportional font flag				;
;									;
; Error Returns:							;
;	AX = 0								;
;									;
; Registers Preserved:							;
; 									;
; Registers Destroyed:							;
; 									;
; Calls:								;
; 									;
; History:								;
; 									;
; Fri 06 Jan 1989  -- Written by Sankar.				;
;									;
;-----------------------------------------------------------------------;

	assumes	ds, nothing
	assumes	es, nothing

cProc	GetExpWinVer,<PUBLIC,FAR>, <si,di>
	parmW   hInstance
cBegin	
	cCall	GetExePtr,<hInstance>
	or	ax,ax
	jz	err_GetExpWinVer
	mov	es,ax
	mov	ax,es:[ne_expver]
	mov	dx,es:[ne_flags]
	and	dx,NEWINPROT
; error if offsets don't match our defines - In which case find the right
; offsets and changes the defines in mvdm\inc\tdb16.h

.erre (NE_LOWINVER_OFFSET EQ ne_expver)
.erre (NE_HIWINVER_OFFSET EQ ne_flags)

err_GetExpWinVer:

cEnd	


;-----------------------------------------------------------------------;
; MyAlloc								;
;									;
; Private interface to memory manager                                   ;
; 									;
; Arguments:								;
;	parmW   aflags							;
;	parmW   nsize							;
;	parmW   nelem							;
; 									;
; Returns:								;
; 									;
; Error Returns:							;
;	AX = Handle							;
;	DX = Seg Address						;
; 									;
; Registers Preserved:							;
;	DI,SI,DS							;
; 									;
; Registers Destroyed:							;
;	BX,CX,ES							;
; 									;
; Calls:								;
;	GlobalAlloc							;
;	MyLock								;
; 									;
; History:								;
; 									;
;  Wed Apr 08, 1987 06:22:57a  -by-  David N. Weise   [davidw]          ;
; Wrote it.								;
;-----------------------------------------------------------------------;
	assumes	ds, nothing
	assumes	es, nothing


cProc	MyAllocLinear,<PUBLIC,NEAR>
	; Same as MyAlloc, except for non-brain-dead size parameter
	parmW   aflags
	parmD   dwBytes
cBegin
	jmps	MyAllocNotBrainDead
cEnd


	assumes	ds, nothing
	assumes	es, nothing

cProc	MyAlloc,<PUBLIC,NEAR>
	parmW   aflags
	parmD	dwBytes
;	parmW   nsize
;	parmW   nelem
cBegin
	xor	dx,dx
	mov	ax,seg_dwBytes	;nsize
	mov	cx,off_dwBytes	;nelem
	jcxz	ma3
ma2:
	shl	ax,1
	rcl	dx,1
	loop	ma2
ma3:
	mov	seg_dwBytes, dx
	mov	off_dwBytes, ax
MyAllocNotBrainDead:
	SetKernelDS	es
	mov	cx,aflags
	mov	al,NSTYPE
	and	al,cl			; al has SEGTYPE
	mov	bx,NSDISCARD
	and	bx,cx
	jz	@F
	shr	bx,1
	shr	bx,1
	shr	bx,1
	shr	bx,1			; BX has GA_DISCARDABLE
	cmp	al,NSCODE
	jne	@F
	or	bl,GA_DISCCODE		; Allocating discardable code
@@:

	cmp	al,NSDATA
	jne	@F
	and	cx,NOT NSWINCODE	; undo Excel bogusness
	or	bl,GA_DGROUP		; Allocating automatic data segment
@@:

	test	cl,NSMOVE
	jz	@F
	or	bl,GA_MOVEABLE
@@:

	cmp	al,NSTYPE
	jz	@F
	or	bh,GA_CODE_DATA
@@:

	cCall	IGlobalAlloc,<bx,dwBytes>	 ;dxax>

	assumes	es, nothing
	push	ax
	test	al,GA_FIXED
	jnz	@F
	cCall	MyLock,<ax>
@@:
	pop	dx
cEnd


;
; MyLock( hseg ) - Procedure to return the physical segment address of
; the passed handle.
;
;;;cProc	MyLock,<PUBLIC,NEAR>
;;;	parmW   hseg
;;;cBegin
;;;	cCall	IGlobalHandle,<hseg>
;;;	xchg	dx,ax
;;;cEnd


;-----------------------------------------------------------------------;
; MyFree								;
; 									;
; Frees a segment allocated by MyAlloc.					;
; 									;
; Arguments:								;
; 									;
; Returns:								;
; 									;
; Error Returns:							;
; 									;
; Registers Preserved:							;
; 									;
; Registers Destroyed:							;
; 									;
; Calls:								;
; 									;
; History:								;
; 									;
;  Tue Dec 09, 1986 12:48:43p  -by-  David N. Weise   [davidw]          ;
; Added this nifty comment block.					;
;-----------------------------------------------------------------------;

	assumes	ds, nothing
	assumes	es, nothing

cProc	MyFree,<PUBLIC,NEAR>
	parmW   hseg
	localW  pseg
cBegin
	mov	bx,hseg
	or	bx,bx
	jz	mf3
	mov	ax,bx
	xor	cx,cx
	test	bl,GA_FIXED
	jnz	mf0a

	push	bx
	cCall	GlobalFlags,<bx>
	mov	cx, ax
	xor	ax, ax
	pop	bx
	xchg	ch, cl
	test	cl, HE_DISCARDED
	jnz	mf0a
	mov	ax, bx
	HtoS	ax

mf0a:
if KDEBUG
	push	cx
endif
	mov	pseg,ax
	or	ax,ax
	jz	mf1
mf0:
if SDEBUG
	cCall	DebugFreeSegment,<pseg,0>
endif
mf1:
if KDEBUG
	pop	cx
	or	ch,ch
	jz	mf2
mf1a:
	push	cx
	cCall	IGlobalUnfix,<hseg>	 ; Prevent RIP if freeing locked DS
	pop	cx
	dec	ch
	or	ch,ch			; If still lock, do it again
	jnz	mf1a
endif
mf2:
	cCall	IGlobalFree,<hseg>
mf3:
cEnd

;-----------------------------------------------------------------------;
; EntProcAddress
;
; Returns the fixed address of a procedure.
;
; Entry:
;
; Returns:
;	DX:AX = thunk for moveable
;	DX:AX = procedure for fixed
;	AX = constant, ES:BX => constant for absolutes
; Registers Destroyed:
;
; History:
;  Wed 30-Nov-1988 19:39:05  -by-  David N. Weise  [davidw]
;
;-----------------------------------------------------------------------;

	assumes	ds, nothing
	assumes	es, nothing

cProc	EntProcAddress,<PUBLIC,NEAR>,<si,di>
	parmW	hExe
	parmW	entno
if KDEBUG
	parmW	bNoRip		; if 1 don't RIP for error, 0 -> do the RIP
endif

cBegin
	mov	es,hExe
	mov	cx,entno
	and	cx,7fffh		; clear ResidentName bit (#5108 donc)
	jcxz	entfail
	dec	cx
	mov	si,es:[ne_enttab]

entloop:
	mov	ax, es:[si.PM_entstart]
	cmp	cx, ax			; Below this block?
	jb	entfail			;   yes, must be invalid!
	cmp	cx, es:[si.PM_entend]	; Above this block?
	jae	entnext			;  yes, go to next block
	sub	cx, ax			; Found the right block, get offset
	mov	bx, cx
	shl	cx, 1
	add	bx, cx
	add	bx, cx			; bx = cx*5
	lea	si, [si+bx+size PM_entstruc]
	mov	bx, si
	jmps	gotent
entnext:
	mov	si, es:[si.PM_entnext]	; Next block
	or	si, si
	jnz	entloop
	jmps	entfail

entfail:
if KDEBUG
	cmp	bNoRip,0
	jnz	dont_rip_here
	mov	bx,entno
	krDebugOut <DEB_WARN or DEB_krLoadSeg>, "Invalid ordinal reference (##BX) to %ES1"
;	kerror	ERR_LDORD,<Invalid ordinal reference to >,es,bx
dont_rip_here:
endif
	xor	dx,dx
	xor	ax,ax
	jmps	entdone

; Here if the current block has the entry we want

gotabs:
	add	bx,pentoffset		; make ES:BX point to constant (SLIME!)
	mov	dx,-1			; make != 0 since abs might be!
	jmps	gotent1			; Offset is symbol value

gotent:
	xor	ax, ax
	mov	al, es:[bx].penttype 	; Get segno/type field
	mov	si,es:[bx].pentoffset
	cmp	al,ENT_ABSSEG		; If segno field absoulute segment
	je	gotabs			; Yes, have absolute symbol

	cmp	al, ENT_MOVEABLE
	je	gotmoveable

	.errnz	10 - SIZE NEW_SEG1
	; ax = segno
	push	bx
	mov	bx, es:[ne_segtab]	; see if really fixed
	mov	cx, ax			; look up in seg table
	dec	cx
	shl	cx, 1			; get segtable + (segno-1)*10
	add	bx, cx
	shl	cx, 2
	add	bx, cx
	test	es:[bx].ns_flags, NSMOVE + NSALLOCED
	pop	bx
	jnz	gotmoveable

	mov	cx,-1			; Fixed, make sure it's loaded
	cCall	LoadSegment,<es,ax,cx,cx>
	or	ax,ax
	mov	dx,ax
	jnz	gotent1
	jmp	entfail

gotmoveable:
	xor	ax,ax
	mov	al,es:[bx].pentsegno	; Segment number
	dec	ax
	shl	ax,1
	mov	di,ax
	shl	ax,2
	add	di,ax
	.errnz	10 - SIZE NEW_SEG1
	add	di,es:[ne_segtab]

	mov	dx,es:[di].ns_handle
	or	dx, dx
	jnz	ok
	mov	ax, dx			; No handle, probably from an aborted
	jmps	entdone			; LoadModule - just return 0:0
ok:

	Handle_To_Sel	dl

gotent1:
	mov	ax,si

entdone:
	mov	cx,ax
	or	cx,dx
cEnd


;-----------------------------------------------------------------------;
; FindOrdinal								;
; 									;
; Searches the resident and non-resident name tables for a procedure	;
; name and return its corresponding entry ordinal.			;
; 									;
; Arguments:								;
;	parmW   hExe							;
;	parmD	lpname	pointer name, strings starts with length	;
;	parmW	fh	file handle NOT to be discarded from cache	;
; 									;
; Returns:								;
;	AX = ordinal number						;
;									;
; Error Returns:							;
; 									;
; Registers Preserved:							;
; 									;
; Registers Destroyed:							;
; 									;
; Calls:								;
;	MyUpper								;
;	LoadNRTable							;
;	FreeNRTable							;
; 									;
; History:								;
; 									;
;  Tue 09-May-1989 18:38:04  -by-  David N. Weise  [davidw]		;
; Added the batching if out of memory.					;
;									;
;  Thu Sep 17, 1987 08:55:05p  -by-  David N. Weise   [davidw]          ;
; Added this nifty comment block and fixed it.				;
;-----------------------------------------------------------------------;

	assumes	ds, nothing
	assumes	es, nothing

CLNRBUFFER	equ	150

cProc	FindOrdinal,<PUBLIC,NEAR>,<si,di>
	parmW   hExe
	parmD	lpname
	parmW	fh

if ROM
	localW	fInROM
endif
	localD	oNRTable		; if batching, continue here
	localV	LoadNRbuffer,CLNRBUFFER ; if batching this is temp buffer
cBegin
	xor	ax,ax
	mov	oNRTable.hi,ax
	mov	oNRTable.lo,ax
if ROM
	mov	fInROM,ax		; assume module not in ROM
endif
	les	si,lpname
	cmp	byte ptr es:[si+1],'#'
	je	foint

fonorm:	push	ds
	mov	ds,hExe
if ROM
	test	ds:[ne_flags],NEMODINROM	; is module actually in ROM?
	jz	@f
	inc	fInROM
@@:
endif
	mov	si,ds:[ne_restab]
	cld

foinit:	xor	ax,ax			; Skip module name or description
	lodsb
	add	si,ax
	inc	si
	inc	si

foloop: lodsb				; get length of entry
	les	di,lpname
	mov	cx,ax
	jcxz	fodone			; no more entries?
	cmp	es:[di],al		; do lengths match?
	jne	noteq
	inc	di
fo_find:
	mov	al,es:[di]
	call	MyUpper
	mov	bl,ds:[si]
	inc	si
	inc	di
	cmp	al,bl
	jne	noteq1
	loop	fo_find
;	repe	cmpsb
;	jne	noteq
	lodsw				; get ordinal number!
	mov	bx,ds
	pop	ds
	cmp	hExe,bx 		; did we load the nrtable?
	jnz	foexit_j
	jmp	foexit1
foexit_j:
	jmp	foexit

noteq1:	dec	cx
noteq:	add	si,cx
	inc	si
	inc	si
	jmps	foloop

; Here if pName points to string of the form:  #nnnn

foint:	lods	byte ptr es:[si]	; nbytes = *pName++
	mov	cl,al
	xor	ch,ch

	dec	cx			; ignore #
	inc	si

	xor	ax,ax			; sum = 0
foint0:	mov	dx,ax
	lods	byte ptr es:[si]	; c = *pName++
	sub	al,'0'			; if (!isdigit(c))
	cmp	al,9
	ja	fonorm			;	treat like normal
	xor	ah,ah
	mov	bx,ax			; sum = (sum * 10) + (c - '0')
	mov	al,10
	mul	dx
	add	ax,bx
	loop	foint0
	jmp	foexit1

fodone:	mov	bx,ds
	pop	ds
;%out help me				; what was this line for?
	mov	cx,oNRTable.hi
	cmp	cx,oNRTable.lo
	jnz	fo_batching
	cmp	hExe,bx 		; have we looked at NRTable yet?
if ROM
	jne	foexit_j
else
	jne	foexit
endif

if ROM
	cmp	fInROM,0		; this module in ROM?
	jz	fo_nr_not_in_rom
	cCall	FindROMNRTable,<hExe>	; yes, get selector to ROM NR Table
	mov	fInROM,ax
	push	ds
	mov	ds,ax			; ds -> ROM NR table
	xor	bx,bx
	mov	bl,ds:[0]		; skip over first NR table entry
	lea	si,[bx+3]		;   (the module description string)
	xor	ax,ax
	jmp	foloop
fo_nr_not_in_ROM:
endif

fo_batching:
	xor	bx,bx
	mov	ax,fh
;;;	cmp	ax,-1
;;;	jz	no_file_handle

	SetKernelDS	ES
;;;	mov	dx, topPDB
;;;	mov	es, curTDB
;;;	UnSetKernelDS	es
;;;	mov	ax, es:[TDB_PDB]
;;;
;;;	cmp	dx, cur_dos_pdb
;;;	jz	@F
;;;	mov	bx,ax
;;;@@:
	mov	bx, Win_PDB
	UnSetKernelDS

	mov	dx, -1
	cCall	GetCachedFileHandle,<hexe,ax,dx>
no_file_handle:
	push	bx
	lea	cx,LoadNRbuffer
	mov	dx,CLNRBUFFER
	cCall	LoadNRTable,<hexe,ax,oNRTable,ss,cx,dx>
if KDEBUG
	push	es
	push	di
	les	di, [lpName]
	krDebugOut	<DEB_TRACE or DEB_krLoadSeg>, "    looking for @ES:DI"
	pop	di
	pop	es
endif
	pop	si
	or	si,si
	jz	@F
;;;	push	ax
;;;	push	bx
;;;	mov	bx,si
;;;	mov	ah,50h
;;;	DOSCALL
;;;	pop	bx
;;;	pop	ax
	push	es
	SetKernelDS	ES
	mov	Win_PDB, si
	pop	es
	UnSetKernelDS	ES
@@:	mov	oNRTable.hi,cx
	mov	oNRTable.lo,bx
	push	ds
	mov	ds,dx
	mov	si,ax
	or	ax,dx			; did we get a table?
	jz	@F
	xor	ax,ax
	jmp	foloop
@@:	pop	ds
foexit: push	ax
if ROM
	cmp	fInROM,0		; this module in ROM
	jz	@f
	cCall	FreeSelector,<fInROM>	; yes, free ROM NR table selector
	jmps	foexit0
@@:
endif
	mov	ax,ne_nrestab
	cCall	FreeNRTable,<hExe,ax>
foexit0:
	pop	ax
foexit1:

;??? commented out 3/7/88 by rong
;??? we should put this back in once everyone has the new keyboard driver
;if KDEBUG
;	or	ax,ax
;	jnz	foexit2
;	les	bx,lpname
;	inc	bx
;	kerror	ERR_LDNAME,<Invalid procedure name >,es,bx
;	xor	ax,ax
;foexit2:
;endif
cEnd


if ROM	;----------------------------------------------------------------

;-----------------------------------------------------------------------
; FindROMNRTable
;
; Returns a selector to the ROM copy of the Non-Resident name table for
; a module stored in ROM.
;
; Arguments:
;	parmW	hExe
;
; Returns:
;	AX = selector mapping NR table
;
;-----------------------------------------------------------------------

	assumes	ds, nothing
	assumes	es, nothing

cProc	FindROMNRTable,<PUBLIC,NEAR>,<ds>
	parmW   hExe
cBegin
	mov	ds,hExe
	mov	ax,word ptr ds:[ne_nrestab]
	mov	bx,word ptr ds:[ne_nrestab+2]
	cCall	alloc_data_sel16,<bx,ax,1000h>
if PMODE32
	cCall	HocusROMBase, <ax>
endif
if KDEBUG
	or	ax,ax
	jnz	@f
	int	3
@@:
endif
cEnd

endif ;ROM	---------------------------------------------------------

; Search the list of new EXE headers for the passed executable file name
; (no path)
;
; this must be resident so we can search for modules in the file handle
; cache from the int 21 handler -- craigc
;

cProc	ResidentFindExeFile,<PUBLIC,FAR>,<ds,si,di>
    parmD   pname
cBegin
	SetKernelDS

	mov	ax,hExeHead
ffloop:
	or	ax,ax
	jz	ffdone
	mov	es,ax
	mov	di,es:[ne_pfileinfo]
	or	di,di
	jz	ffnext

;
;	Double Byte Character is not able to search from the end of string,
;	so this function must search from the top of string.
;
ifdef DBCS
	lea	si,[di.opFile]		; get address of file name
	mov	cl,es:[di.opLen]	; get structure length
	xor	ch,ch
	add	cx,di
	mov	di,cx			; save end address
	sub	cx,si			; get length of file name
	mov	bx,si			; save top address of file name
	cld
delineator_loop:
	lods	byte ptr es:[si]
	call	MyIsDBCSLeadByte
	jc	delineator_notlead	; if not DBCS lead byte
	dec	cx
	jcxz	delineator_next
	inc	si
	loop	delineator_loop
	jmp	delineator_next
delineator_notlead:
	cmp	al,"\"
	jz	found_delineator
	cmp	al,":"
	jz	found_delineator
	loop	delineator_loop
	jmp	delineator_next
found_delineator:
	mov	bx,si			; save delineator address
	loop	delineator_loop
delineator_next:
	xchg	bx,di			; set address of file name to di
	sub	bx,di			; get lenfth of file name
else
	mov	si,di
	xor	cx,cx
	mov	cl,es:[di]
	add	si,cx
	dec	si
	std
	xor	bx,bx
delineator_loop:			; look for beginning of name
	lods	byte ptr es:[si]
	cmp	al,"\"
	jz	found_delineator
	cmp	al,":"
	jz	found_delineator
	inc	bx
	loop	delineator_loop
	dec	si
found_delineator:			; ES:SI -> before name
	mov	di,si
	inc	di
	inc	di
endif

	lds	si,pname
	UnSetKernelDS
	mov	cx,bx
	cld
	repe	cmpsb
	mov	ax,es
	je	ffdone
ffnext:
	mov	ax,word ptr es:[ne_pnextexe]
	jmp	ffloop
ffdone:
cEnd

sEnd	CODE

externFP FarLoadSegment

sBegin	NRESCODE
assumes CS,NRESCODE
assumes DS,NOTHING
assumes ES,NOTHING

externNP DelModule
externNP MapDStoDATA

cProc	FindExeFile,<PUBLIC,NEAR>
    parmD   pFile
cBegin
    cCall   ResidentFindExeFile, <pFile>
cEnd


; Search the list of new EXE headers for the passed executable name

cProc	FindExeInfo,<PUBLIC,NEAR>,<ds,si,di>
    parmD   pname
    parmW   nchars
cBegin

	cCall	MapDStoDATA
	ReSetKernelDS

	mov	bx,nchars
	mov	ax,hExeHead
feloop:
	or	ax,ax
	jz	fedone
	mov	es,ax
	mov	di,es:[ne_restab]
	cmp	es:[di],bl
	jne	fenext
	inc	di
	lds	si,pname
	UnSetKernelDS
	mov	cx,bx
	repe	cmpsb
	je	fedone
fenext:
	mov	ax,word ptr es:[ne_pnextexe]
	jmp	feloop
fedone:
cEnd

cProc	FarFindExeInfo,<PUBLIC,FAR>
	parmD	pname
	parmW	nchars
cBegin
	cCall	FindExeInfo,<pname,nchars>
cEnd


;
; IncExeUsage( hExe ) - procedure to increment the usage count of this
; EXE header.  Indirectly increments the usage count of all the EXE
; headers it points to.
;
cProc	IncExeUsage,<PUBLIC,NEAR>,<ax,di>
	parmW   hexe
cBegin
	mov	cx,hexe
	jcxz	iexj
	mov	es,cx
	cmp	es:[ne_magic],NEMAGIC
	jne	iexj
	test	es:[ne_usage],8000h
	jz	iego
iexj:
	krDebugOut	<DEB_ERROR or DEB_KRLOADMOD>, "IncExeUsage(#ES) not DLL"
	jmp	iex
iego:

	cmp	es:[ne_usage], 4000h
	jb	OKusage
	krDebugOut	DEB_FERROR, "IncExeUsage: ne_usage overflow"
OKusage:

		;
		; Save time and space by saving stuff on stack
		; rather than recursing.
		;

	or	es:[ne_usage], 8000h
NextExe0:
	or	es:[ne_usage], 4000h		; Mark node visited
	inc	es:[ne_usage]
;if kdebug
;	push	ax
;	mov	ax, es:[ne_usage]
;	krDebugOut <DEB_TRACE or DEB_krLoadMod>, "IncExeUsage(%ES0) #ax"
;	pop	ax
;endif
	mov	cx,es:[ne_cmod]
	jcxz	NoDeps0
	mov	di,es:[ne_modtab]
ieloop:
	push	es
	cmp	word ptr es:[di], 0
	je	ieloop1
	lar	ax, es:[di]			; Make sure valid selector
	jnz	ieloop1
	mov	es, es:[di]
	cmp	es:[ne_magic],NEMAGIC
	jne	ieloop1
	test	es:[ne_usage], 0C000h
	jnz	ieloop1
	push	cx
	push	di				; Fake recursion
	jmp	NextExe0
NextExeDone0:					; Return from fake recursion
	pop	di
	pop	cx
ieloop1:
	pop	es
	add	di,2
	loop	ieloop

NoDeps0:
	mov	cx, es
	cmp	cx, hExe
	jne	NextExeDone0

NextExe1:
	and	es:[ne_usage], NOT 4000h	; Mark node visited
	mov	cx,es:[ne_cmod]
	jcxz	NoDeps1
	mov	di,es:[ne_modtab]
UnMarkLoop:
	push	es
	cmp	word ptr es:[di], 0
	je	UnMarkLoop1
	lar	ax, es:[di]			; Make sure valid selector
	jnz	UnMarkLoop1
	mov	es, es:[di]
	cmp	es:[ne_magic],NEMAGIC
	jne	UnMarkLoop1
	test	es:[ne_usage], 08000h
	jnz	UnMarkLoop1
	test	es:[ne_usage], 04000h
	jz	UnMarkLoop1
	push	cx
	push	di				; Fake recursion
	jmp	NextExe1
NextExeDone1:					; Return from fake recursion
	pop	di
	pop	cx
UnMarkLoop1:
	pop	es
	add	di,2
	loop	UnMarkLoop

NoDeps1:
	mov	cx, es
	cmp	cx, hExe
	jne	NextExeDone1

	xor	es:[ne_usage], 8000h
iex:
cEnd

;-----------------------------------------------------------------------;
; DecExeUsage								;
; 									;
; Decrements the usage count of the given EXE header.  Indirectly	;
; decrements the usage count of all the EXE headers it points to.	;
; 									;
; Arguments:								;
;	parmW   hexe							;
; 									;
; Returns:								;
;	ZF = 1 if usage count is now zero.				;
; 									;
; Error Returns:							;
; 									;
; Registers Preserved:							;
;	DI,SI,DS							;
;									;
; Registers Destroyed:							;
; 	AX,BX,CX,DX,ES							;
;									;
; Calls:								;
;	DecExeUsage							;
;	DelModule							;
; 									;
; History:								;
; 									;
;  Mon Sep 21, 1987 01:21:00p  -by-  David N. Weise   [davidw]          ;
; Added this nifty comment block.					;
;-----------------------------------------------------------------------;

cProc	DecExeUsage,<PUBLIC,NEAR>,<ds,di,si>
	parmW   hexe
cBegin
	call	MapDStoDATA
	ReSetKernelDS

	xor	si,si
	mov	cx,hexe
	xor	ax,ax
	jcxz	dexj
	mov	es,cx
	cmp	es:[si].ne_magic,NEMAGIC
	jne	dexj
	test	es:[si].ne_usage,8000h
	jz	dego
dexj:
	krDebugOut	<DEB_ERROR or DEB_KRLOADMOD>, "DecExeUsage(#ES) not DLL"
	jmp	dex
dego:

		;
		; Save time and space by saving stuff on stack
		; rather than recursing.
		;

	dec	es:[si].ne_usage
	or	es:[si].ne_usage, 8000h
;if kdebug
;	push	ax
;	mov	ax, es:[si].ne_usage
;	krDebugOut <DEB_TRACE or DEB_krLoadMod>, "DecExeUsage(%ES0) #ax"
;	pop	ax
;endif
NextExe2:
	or	es:[si].ne_usage, 4000h		; Mark node visited
	mov	cx,es:[si].ne_cmod
	jcxz	NoDeps2
	mov	di,es:[si].ne_modtab
MarkLoop2:
	push	es
	cmp	si, es:[di]
	je	MarkLoop3
	lar	ax, es:[di]			; Make sure valid selector
	jnz	MarkLoop3
	mov	es, es:[di]
	cmp	es:[si].ne_magic,NEMAGIC
	jne	MarkLoop3
	test	es:[si].ne_usage, 0C000h
	jnz	MarkLoop3
	push	cx
	push	di				; Fake recursion
	jmp	NextExe2
NextExeDone2:					; Return from fake recursion
	pop	di
	pop	cx
MarkLoop3:
	pop	es
	add	di,2
	loop	MarkLoop2

NoDeps2:
	mov	cx, es
	cmp	cx, hExe
	jne	NextExeDone2

        xor     cx, cx
        push    cx                              ; End of list of Exes to delete
	mov	di, hExeHead			; Scan Exes once to dec them
scan_exes:
	or	di, di
	jz	de_done
	mov	es, di
	mov	di, es:[si].ne_pnextexe
	test	es:[si].ne_usage, 4000h
	jz	scan_exes
	and	es:[si].ne_usage, NOT 4000h	; Remove the mark
	test	es:[si].ne_usage, 8000h		; Skip this one?
	jnz	scan_exes
;	krDebugOut <DEB_TRACE or DEB_krLoadMod>, "DecExeUsage dependent %ES0"
	dec	es:[si].ne_usage
        jnz     scan_exes
        push    es                              ; We will delete this one
        jmps    scan_exes


de_done:				; Call WEP each module before
	mov	bx, sp			; we free any modules
de_done0:
	mov	cx, ss:[bx]
	add	bx, 2
	jcxz	de_done1
	push	bx
	cCall	CallWEP, <cx, 0>
	pop	bx
	jmps	de_done0


de_done1:
        pop     cx                              ; Get next module to delete
        jcxz    all_deleted
        cCall   DelModule,<cx>                  ; Delete him
	jmps    de_done1

all_deleted:
	mov	es, hExe
	and	es:[si].ne_usage,NOT 0C000h
dex:
cEnd


;
; StartProcAddress( hExe ) - procedure to return the fixed address of
; a new EXE start procedure
;
cProc	StartProcAddress,<PUBLIC,NEAR>,<di>
	parmW   hexe
	parmW   fh
cBegin
	mov	es,hexe
	mov	di,ne_csip
	xor	dx,dx
	mov	ax,es:[di+2]
	or	ax,ax
	jz	sp1
	mov	di,es:[di]
	cCall	FarLoadSegment,<es,ax,fh,fh>
	jcxz	sp1
	mov	ax,di			; DX:AX is start address of module
sp1:					; (DX is really a handle)
	mov	cx,ax
	or	cx,dx
cEnd



; GetStackPtr - returns the initial SS:SP for a module.
;
cProc GetStackPtr,<PUBLIC,NEAR>,<si>
	parmW   hExe
cBegin
	mov	es,hExe
if KDEBUG
	cmp	es:[ne_sssp].sel,0
	jnz	@F
	mov	cx,ne_sssp
	fkerror 0,<Invalid stack segment>,es,cx
@@:
endif
	cmp	es:[ne_sssp].off,0
	jne	re3
	mov	dx,es:[ne_stack]
	mov	bx,es:[ne_pautodata]
	or	bx,bx
	jz	re2
	add	dx,es:[bx].ns_minalloc
re2:	and	dx,0FFFEh		; Word aligned stack
	mov	word ptr es:[ne_sssp],dx

re3:	mov	dx,es:[ne_sssp].sel
	mov	ax,es:[ne_sssp].off
	push	ax
	mov	cx,-1
	cCall	FarLoadSegment,<es,dx,cx,cx>
	pop	ax			; Handle in DX and offset in AX
cEnd




;
; GetInstance( hExe ) - Procedure to return the instance handle for
; the current automatic data segment associated with the passed exe
;
cProc	GetInstance,<PUBLIC,NEAR>
	parmW   hexe
cBegin
	mov	es,hexe
	mov	ax,es:[ne_flags]
	test	ax,NEINST+NESOLO
	mov	ax,es
	jz	gidone
	mov	bx,es:[ne_pautodata]
	or	bx,bx
	jz	gidone
	mov	ax,es:[bx].ns_handle
gidone:
	mov	cx,ax
cEnd

sEnd	NRESCODE

end