home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / prgramer / info / migr.inf (.txt) < prev    next >
Encoding:
OS/2 Help File  |  1993-01-03  |  15.0 KB  |  421 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. Why this file? ΓòÉΓòÉΓòÉ
  3.  
  4.  I've been converting hundreds of kilobytes of old C code, running under PC DOS 
  5. and OS/2 1.x and compiled with Microsoft C 5.x and 6.x, to run with IBM C Set/2 
  6. under OS/2 2.x. As I solved the problems that I encountered, I took these notes 
  7. to help me remember what I did if I encounter the same problem again. I then 
  8. converted this file into IPF as an exercise in the latter and am distributing 
  9. it, hoping that it will be useful to others. These notes are meant to 
  10. supplement, not replace, the C Set/2 User's Guide and Migration Guide, although 
  11. I found them pretty useless. They are not, nor were ever meant to be, 
  12. well-organized. 
  13.  
  14.  I would greatly appreciate all comments, suggestions, job offers :), et al. 
  15. E-mail me at DLV@DM.COM, or call me at +1-718-261-6839. 
  16.  
  17.  
  18. ΓòÉΓòÉΓòÉ 2. Configuring the compiler ΓòÉΓòÉΓòÉ
  19.  
  20.  The following lines in my CONFIG.SYS  configure the compiler: 
  21.  
  22. libpath=...;C:\IBMWF\DLL;C:\TOOLKT20\DLL;C:\IBMC\DLL;... 
  23. set path=...;C:\IBMWF\BIN;C:\TOOLKT20\OS2BIN;C:\IBMC\BIN;... 
  24. set dpath=...;C:\IBMC\LOCALE;C:\IBMC\HELP 
  25. set icc=-Ka+ -Kb+ -Kc+ -Ko+ -Kp+ -Kx+ -N10 -W3 -Ss+ -G4 -Gf+ -Gs+ -O+ -Q+ 
  26. -DINCL_32 -Gd+ 
  27. set tempmem=on 
  28. set lib=C:\IBMLAN\NETSRC\LIB;C:\TOOLKT20\OS2LIB;C:\IBMC\LIB 
  29. set include=C:\IBMLAN\NETSRC\H;C:\TOOLKT20\C\OS2H;C:\IBMC\INCLUDE 
  30. set tmp=C:\TEMP\ 
  31.  
  32.  Explanation of the ICC options: 
  33.  
  34. -K* enables some useful warnings 
  35. -N10 stops after 10 errors 
  36. -Ss+ allows //, the C++ extension for comment 
  37. -G4 optimizes for 486, rather than 386 
  38. -Gf+ faster, non-IEEE, floating point 
  39. -Gs+ no stack probes 
  40. -O+ optimize 
  41. -Q+ logo 
  42. -DINCL_32 used in various .h files (LAN Server) 
  43. -Gd+ DLL runtime for smaller EXE 
  44.  
  45.  Note: if you use -gd+, then at runtime DPATH must include 
  46. C:\IBMC\LOCALE;C:\IBMC\HELP. If you intend to run the EXE file on machines 
  47. where ICC is not installed, you must specify -gd-. 
  48.  
  49.  You may also want to specify -Sm to enable the migration features (see the 
  50. section on those). 
  51.  
  52.  
  53. ΓòÉΓòÉΓòÉ 3. At the beginning ΓòÉΓòÉΓòÉ
  54.  
  55.  Look through the #include files and get rid of the ones you don't need. In 
  56. particular, <dos.h> does not exist and <fcntl.h> and <io.h> should be 
  57. eliminated. 
  58.  
  59.  Whenever you rely on an integer variable being 16, rather than 32 bits, you 
  60. must declare it to be short. In my practice this happens usually when 
  61. describing out structures used for binary i/o on files. For example, 
  62.  
  63. static _Packed struct {
  64. char header[7];
  65. int num_row;
  66. char quote;
  67. char line[8];
  68. char trailer;
  69. } rec;
  70.  
  71.  The program will compile, but when an attempt it made to read this structure 
  72. from a file, the quote field will receive the wrong byte. This is because 
  73. num_row should have been explicitly declared short. Always declare such fields 
  74. long or short. 
  75.  
  76.  Also note that if _Packed were not specified, the compiler would insert a 
  77. filler byte before num_row to align it on 16-bit boundary and leading to 
  78. incorrect results.  long double (80-bit temporary real) are aligned on 16-byte 
  79. boundary, with 4 bytes wasted. This differs from some C compilers that align 
  80. them on 10-byte boundary. 
  81.  
  82.  Changed handling of char type may lead to bugs. In many old compilers, the 
  83. default for char is signed. In icc, the default is unsigned. This makes sense 
  84. if the chars contain 8-bit text (e.g., French or German). If the char variables 
  85. really contain numbers, why not use int. 
  86.  
  87.  Old code: 
  88.  
  89. char c;
  90.  
  91. c=-1;
  92.  produces a warning and c becomes 255. 
  93.  
  94.  New code: 
  95.  
  96. signed char c;
  97.  You can specify -J+ to make default  char signed. 
  98.  
  99.  
  100. ΓòÉΓòÉΓòÉ 4. Migrating from old compilers ΓòÉΓòÉΓòÉ
  101.  
  102.  These notes refer to migrating from really old compilers, such as MS C 5.x. 
  103.  
  104.  Provide new-style prototypes for every function. 
  105.  
  106.  Old code: 
  107.  
  108. myfunc(a,b)
  109. int a;
  110. int b;
  111. {
  112.  ...
  113. }
  114.  
  115.  New code: 
  116.  
  117. static int myfunc(int a,int b);
  118.  ...
  119. int myfunc(int a,int b)
  120. {
  121.  ...
  122. }
  123.  
  124.  Do not omit the ... when specifying variable arguments. 
  125.  
  126.  Old code: 
  127.  
  128. #include <stdarg.h>
  129.  
  130. void wrlog(char *s,);
  131.  
  132.  New code: 
  133.  
  134. static void wrlog(char *s,...);
  135.  ...
  136. void wrlog(char *s,...)
  137. {
  138. va_list arg_ptr;
  139.  
  140. va_start(arg_ptr, s);
  141. vprintf(s,arg_ptr);
  142. fflush(stdout);
  143. vfprintf(logfptr,s,arg_ptr);
  144. fflush(logfptr);
  145. va_end(arg_ptr);
  146. }
  147.  Beware of trigraphs! E.g.,  dbfcmd(..."update #t set name='???'\n");  will 
  148. actually put a ^ (caret) in name, leading to an insidious bug. Fortunately, icc 
  149. produces a warning, unlike MS C 6. The solution is to avoid using multiple ?'s. 
  150.  
  151.  You cannot omit type and just declare a variable name: 
  152.  
  153. int myfunc(void)
  154. {
  155. a;
  156.  
  157. a=123...
  158. }
  159.  In icc, say int a. 
  160.  
  161.  NULL is a pointer to void and cannot be compared to 0 without a cast. 
  162.  
  163.  
  164. ΓòÉΓòÉΓòÉ 5. Differences in library functions ΓòÉΓòÉΓòÉ
  165.  
  166.  Replace non-standard functions by their standard equivalents: 
  167. unlink("junkfile"); by remove("junkfile");, onexit by atexit... 
  168.  
  169.  MS C closes all streams when the program terminates, and ICC doesn't. If you 
  170. want this behavior, add a _fclosall() to your atexit handler. 
  171.  
  172.  Under MS C, the atexit handler is not invoked if the program abends. Under icc 
  173. it's always invoked. 
  174.  
  175.  Old code: 
  176.  
  177. int exit_rtn(void);
  178.  ...
  179. if (0!=atexit(exit_rtn))
  180.           error("add exit_rtn() to exit list", 1);
  181.  
  182.  New code: 
  183.  
  184. static void exit_rtn(void);
  185. volatile static int needonexit=1;
  186.  ...
  187. void exit_rtn(void)
  188. {
  189. {
  190. if (needonexit)
  191.  {
  192.  needonexit=0;
  193.  /* logout, hangup, etc. */
  194.  _fcloseall();
  195.  }
  196. }
  197.  
  198.  Note that the routine returns void instead of int. 
  199.  
  200.  Add fflush(stdout); before each scanf. 
  201.  
  202. printf("Enter a number: ");
  203. fflush(stdout);
  204. scanf("%d",&n);
  205.  
  206.  qsort and bsearch are very picky about the comparison function they take as an 
  207. argument. 
  208.  
  209.  Old code: 
  210.  
  211. static int compare_cap(const int *a,const int *b);
  212. static int iwrank[MAX_MASTER];
  213.  ...
  214. int compare_cap(const int *a,const int *b)
  215. {
  216. return (cap[*a]<cap[*b]) ? 1 : ((cap[*a]==cap[*b]) ? 0 : -1);
  217. }
  218.  ...
  219. for (i=0; i<num_work; i++)
  220.          iwrank[i]=i;
  221. qsort(iwrank, num_work, sizeof(int), compare_cap);
  222.  
  223.  New code: 
  224.  
  225. static int compare_cap(const void *a,const void  *b);
  226.  ...
  227. int compare_cap(const void *a,const void  *b)
  228. {
  229. return (cap[*(int*)a]<cap[*(int*)b]) ? 1 :
  230.   ( (cap[*(int*)a]==cap[*(int*)b]) ? 0 :
  231.   -1);
  232. }
  233.  
  234.  Here's an example of a program that uses signal to intercept Control-Break. 
  235. Note that the variables shared between the signal handler and the main program 
  236. must be declared volatile. 
  237.  
  238. #include <signal.h>
  239.  
  240. static void break_handler(int SIG_TYPE); /* prototype */
  241.  
  242. volatile static int num_breaks=0; /* incremented by the handler */
  243.  
  244. int main(void)
  245. {
  246. /* install the signal handler */
  247. if (signal(SIGINT,break_handler)==SIG_ERR)
  248.  perror("Couldn't install breaker handler");
  249.  return(1);
  250.  }
  251. while (num_breaks<10)
  252.  {
  253.  printf("%d",num_breaks); fflush(stdout);
  254.  }
  255. return(0);
  256. }
  257.  
  258. void break_handler(int SIG_TYPE)
  259. {
  260. signal(SIG_TYPE,break_handler); /* reestablish the signal handler */
  261. printf("\nCtrl-Break has been hit!\n");
  262. num_breaks++;
  263. }
  264.  
  265.  
  266. ΓòÉΓòÉΓòÉ 6. Eliminating migration code ΓòÉΓòÉΓòÉ
  267.  
  268.  The rewritings listed here are not really required. You may enable these calls 
  269. by specifying the /Gm option. However read/write seem to be much slower than 
  270. fread/fwrite under ICC and slow down the program significantly when reading a 
  271. large file or when called in a loop. 
  272.  
  273.  Eliminate huge, near, far, cdecl, pascal, and similar keywords. 
  274.  
  275.  Replace calls to open/read/write/close and other functions in <io.h> by calls 
  276. to fopen/fread/fwrite/fclose. Since you are no longer limited to reading and 
  277. writing 32K at a time, your code tends to become much shorter. 
  278.  
  279.  Old code: 
  280.  
  281. char huge *p;
  282. int handle;
  283. unsigned long nread, nleft;
  284.  
  285. if ((handle=open(CUSIPSDIR, O_RDONLY | O_BINARY))==-1)
  286.           error("can't open CUSIP directory",1);
  287.  
  288. /* have to read in 32K chunks */
  289. p=(void*)cusips_dir;
  290. nread=0;
  291. nleft=(long)sizeof(struct cusips_dir_row)*MAX_CUSIPS_DIR;
  292. while (nleft!=0){
  293.           if (nleft>32768)
  294.                       nbytes=32768;
  295.           else
  296.                       nbytes=(int)nleft;
  297.           nbytes=read(handle,p, nbytes);
  298.           if (nbytes==0) break;
  299.           p+=nbytes;
  300.           nleft-=nbytes;
  301.           nread+=nbytes;
  302.           }
  303. num_cusips_dir=nread/sizeof(struct returns_dir_row);
  304.  
  305. close(handle);
  306.  or, if the file is known to be under 32K, just: 
  307.  
  308. nread=read(handle,cusips_dir, sizeof(cusips_dir));
  309.  
  310. while (sizeof(setlist)==read(handle,&setlist,sizeof(setlist)))
  311.  {
  312.  }
  313.  or worse yet, when opening a file for writing, 
  314.  
  315. if ((handle=open(FTEMP, O_CREAT | O_TRUNC | O_BINARY | O_WRONLY,
  316.           S_IREAD | S_IWRITE)) == -1)
  317.  If you omit the third argument, MS C sets the read-only bit in the file's 
  318. directory entry. 
  319.  
  320.  New code: 
  321.  
  322. FILE *fptr;
  323.  
  324. if (NULL==(fptr=fopen(CUSIPSDIR, "rb")))
  325.           error("can't open CUSIP directory",1);
  326. num_cusips_dir=fread(&cusips_dir,sizeof(cusips_dir[0]),MAX_CUSIPS_DIR,fptr);
  327. fclose(fptr);
  328.  
  329.  or in a loop 
  330.  
  331. while (1==fread(&setlist,sizeof(setlist),1,fptr))
  332.  
  333.  If the program uses lseek to determine the file size, here is the standard 
  334. code: 
  335.  
  336. fseek(fptr, 0, SEEK_END);
  337. filesize=ftell(fptr);
  338. fseek(fptr, 0, SEEK_SET);
  339.  
  340.  
  341. ΓòÉΓòÉΓòÉ 7. Linking with 16-bit code ΓòÉΓòÉΓòÉ
  342.  
  343.  These examples deal primarily with the SQL server and LAN Server 2.0, because 
  344. these are the only 16-bit libraries I have to deal with. 
  345.  
  346.  Whenever a pointer is passed to a 16-bit function, it must be cast to *_Seg16. 
  347. Usually this is done automatically if the callee is prototyped as expecting 
  348. such pointer, but if you use variable arguments, you must cast explicitly. 
  349.  
  350.  Old code: 
  351.  
  352. char *cusips;
  353.  
  354. dbfcmd(dbproc,"select price from prices where cusip='%8.8s'",
  355. cusips);
  356.  
  357.  New code: 
  358.  
  359. dbfcmd(dbproc,"select price from prices where cusip='%8.8s'",
  360. (char*_Seg16)cusips);
  361.  
  362.  Likewise, you must specify %ld when passing int. 
  363.  
  364.  Whenever a pointer is returned by a 16-bit code (as a return value from a 
  365. function or as a part of a structure), it must be cast as (type *). Examples: 
  366.  
  367. memcpy(this_line.cusip,(char*)dbdata(dbproc,1),8);
  368.  ...
  369. NetWkstaGetInfo(NULL,10,(char *)wksta_info_out,sizeof(wksta_info_out),&n);
  370. wrlog("Computername=%s Domain=%s Username=%s\n",
  371. (char*)wksta_info_out[0].wki10_computername,
  372. (char*)wksta_info_out[0].wki10_langroup,
  373. (char*)wksta_info_out[0].wki10_username);
  374.  
  375.  
  376. ΓòÉΓòÉΓòÉ 8. Linker ΓòÉΓòÉΓòÉ
  377.  
  378.  Here is a sample .DEF file: 
  379.  
  380. NAME name WINDOWCOMPAT
  381. DESCRIPTION 'This is my program.'
  382. EXETYPE OS2
  383. HEAPSIZE 4000
  384. PROTMODE
  385.  Warning: if you specify HEAPSIZE MAXVAL and the static data is more than 64K, 
  386. the executable won't run, but you'll get no message from the linker. If this 
  387. happens, specify something like HEAPSIZE 4000. 
  388.  
  389.  
  390. ΓòÉΓòÉΓòÉ 9. Performance hints ΓòÉΓòÉΓòÉ
  391.  
  392.  Standard C allows you to write over character constants: 
  393.  
  394. char *x="Abc";
  395.  
  396. *x='X'; *(x+1)='y';
  397.  
  398.  If your program does not do this, put #pragma strings(readonly) at the 
  399. beginning of the program. This way the string constants will be treated as 
  400. constant and multiple occurrences of the same string constant will not be 
  401. duplicated in the executable file. 
  402.  
  403.  If the program does not examine the arguments to main, provide a dummy 
  404. argument set up function: 
  405.  
  406. void _setuparg(void)
  407. {
  408. }
  409.  
  410. int main(void)
  411. {
  412.  ...
  413.  It's not necessary to specify /NOE to the linker. This saves about 500 bytes 
  414. off the executable file and a few milliseconds. 
  415.  
  416.  Declare all functions and global variables that need not be extern (that is, 
  417. are local to this file) to be static, e.g., 
  418.  
  419. static int myfunc(void);
  420. static double x[10];
  421.