home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / maths / rlab / docs / RLEF4F~1 < prev    next >
Encoding:
Text File  |  1997-02-10  |  22.3 KB  |  721 lines

  1. <HTML>
  2. <HEAD>
  3. <TITLE> Rlab2 Reference Manual: Programmer's Reference</TITLE>
  4. </HEAD>
  5. <BODY>
  6. <A HREF="rlab-ref-7.html"><IMG SRC="prev.gif" ALT="Previous"></A>
  7. <A HREF="rlab-ref-9.html"><IMG SRC="next.gif" ALT="Next"></A>
  8. <A HREF="rlab-ref.html#toc8"><IMG SRC="toc.gif" ALT="Contents"></A>
  9. <HR>
  10. <H2><A NAME="s8">8. Programmer's Reference</A></H2>
  11.  
  12.  
  13.  
  14.  
  15. <H2><A NAME="ss8.1">8.1 Introduction</A></H2>
  16.  
  17.  
  18. <P>Rlab2 is not at present an externally visible departure from
  19. Rlab1. However, internally, there are substantial, changes. It is
  20. not really necessary to document the changes, since no programmer's
  21. reference existed for Rlab1. However, documenting the inner-workings
  22. of Rlab2 (here-after referred to simply as Rlab) will not only
  23. benefit the author, but allow advanced users to modify and extend
  24. Rlab2.</P>
  25. <P>In addition to explaining the inner architecture, some justification
  26. will also be provided along the way. I do this mostly so I will
  27. remember why I made certain choices years from now. Additionally, it
  28. may be of some benefit to users.</P>
  29. <P>If you are interested only in writing new builtin, or dynamically
  30. linked functions, you can skip to Section 
  31. <A HREF="#dl-functions">Writing Builtin Functions</A></P>
  32.  
  33.  
  34.  
  35. <H2><A NAME="ss8.2">8.2 Interpreter Operation</A></H2>
  36.  
  37. <P> </P>
  38.  
  39. <H3>Overview</H3>
  40.  
  41.  
  42. <P>In front of the interpreter sit the scanner and the parser. I will
  43. not spend any time discussing the implementation of these pieces,
  44. since they are constructed with fairly common tools: yacc, and
  45. flex. There are many excellent references that cover these
  46. tools.</P>
  47. <P>The interpreter is a stack-based machine. The machine instructions
  48. are called ``op-codes''. Op-codes are to byte codes what RISC
  49. instructions are to CISC instructions. Each op-code is an
  50. integer. Operation information is <EM>not</EM> packed into
  51. words. Instead each op-code is an integer, and any necessary
  52. information occupies its own word. Although this is not space
  53. efficient, it is easier to work with, and usually faster, since the
  54. program does not have to spend any time dissassembling
  55. words. Instructions are aligned on double-word boundaries, further
  56. speeding operation on most architectures.</P>
  57. <P>It is easiest to present the rest of the interpreter in terms of the
  58. data structures:</P>
  59. <P>
  60. <UL>
  61. <LI> The stack data structure is the <CODE>Datum</CODE>. The <CODE>Datum</CODE>
  62. looks like:
  63.  
  64. <BLOCKQUOTE><CODE>
  65. <PRE>
  66. typedef struct _datum Datum;
  67.  
  68. struct _datum
  69. {
  70.   int type;
  71.   union
  72.   {
  73.     double val;
  74.     void *ptr;
  75.   }
  76.   u;
  77. };
  78. </PRE>
  79. </CODE></BLOCKQUOTE>
  80.  
  81.  
  82. The <CODE>type</CODE> element tells the programmer what the <CODE>Datum</CODE>
  83. is carrying, a <CODE>val</CODE>, or a <CODE>ptr</CODE> of some type. <CODE>val</CODE>
  84. is a simple double value used to hold numeric constants. <CODE>ptr</CODE>
  85. is a void pointer to a variable or an entity. Rlab's variables are
  86. contained in the <CODE>ListNode</CODE> structure, since each variable must
  87. be associated with some sort of list, tree, or hash-table.
  88. </LI>
  89. <LI> The <CODE>ListNode</CODE> structure is simple:
  90.  
  91. <BLOCKQUOTE><CODE>
  92. <PRE>
  93. typedef struct _listNode ListNode;
  94.  
  95. struct _listNode
  96. {
  97.   char *key;
  98.   void *ent;
  99.   int scope;
  100.   ListNode *next;
  101.   ListNode *prev;
  102. };
  103. </PRE>
  104. </CODE></BLOCKQUOTE>
  105.  
  106.  
  107. <CODE>ListNode</CODE>s only carry the bare essentials: <CODE>key</CODE> is the
  108. variables name, and is used for identification/lookup. <CODE>Ent</CODE> is
  109. the entity pointer (the thing that actually holds the
  110. data). <CODE>next</CODE>, and <CODE>prev</CODE> are pointers to other
  111. <CODE>ListNodes</CODE>; these are only used when a variable
  112. (<CODE>ListNode</CODE>) is actually installed in a tree or hash-table.
  113. </LI>
  114. <LI> <CODE>Ent</CODE> is short for entity. An entity can contain any
  115. sort of data: matrices, lists, and functions, to name a few. Each
  116. entity can contain only <EM>one</EM> item of data. The <CODE>Ent</CODE>
  117. looks like:
  118.  
  119. <BLOCKQUOTE><CODE>
  120. <PRE>
  121. typedef struct _ent Ent;
  122.  
  123. struct _ent
  124. {
  125.   int refc;
  126.   int type;
  127.   double d;
  128.   void *data;
  129. };
  130. </PRE>
  131. </CODE></BLOCKQUOTE>
  132.  
  133.  
  134. <CODE>refc</CODE> is the reference counter. In Rlab, any number of
  135. variables can point to the same entity. We need to keep track of the
  136. number of variables that actually point to an entitiy, so that we
  137. know when it is safe to delete, or change the entity. Any function
  138. that tries to delete an entity, should really only decrement the
  139. reference count. The entity should not be deleted until the
  140. reference count is zero.
  141.  
  142. The <CODE>type</CODE> element tells functions operating on the entity,
  143. what type of data the entity contains.
  144.  
  145. The <CODE>d</CODE> element is for storing simple numeric scalars, and may
  146. go away in the future.
  147.  
  148. The <CODE>data</CODE> element is a pointer to the actual data. The data
  149. can be anything, in addition to the pre-defined data classes that
  150. Rlab comes with.  I will not discuss the <CODE>data</CODE> structure
  151. because it is arbitrary.
  152. </LI>
  153. </UL>
  154. </P>
  155. <P>The overall operation of the interpreter is easily viewed with an
  156. outline of the steps needed to perform an operation:</P>
  157. <P>
  158. <UL>
  159. <LI> The interpreter makes it way through the instruction
  160. array. For each defined instruction there is a
  161. corresponding block of code, or function that performs the
  162. operation. </LI>
  163. <LI> The operation-function pops data off the data-stack (an array of
  164. Datums) as needed.</LI>
  165. <LI> If a operation-function needs to operate on the data, it
  166. does so through the class-interface.</LI>
  167. <LI> The operation-function pushes data back on the data-stack
  168. as necessary.</LI>
  169. <LI> Interpreter execution continues to the next operation.</LI>
  170. </UL>
  171. </P>
  172.  
  173.  
  174. <H3>Scanner and Parser</H3>
  175.  
  176.  
  177.  
  178.  
  179. <H3>Stack Machine</H3>
  180.  
  181.  
  182.  
  183.  
  184. <H3>Memory Management</H3>
  185.  
  186.  
  187. <P>A consverative garbage collector is used to do the bulk of memory
  188. managemant functions. All data structures are allocated and free'ed
  189. through the garbage-collector functions. Normally, one wouldn't have
  190. to free any objects when a garbage-collector is in use. However,
  191. users can create quite large data objects, and it helps the
  192. garbage-collector (sometimes) to free these objects when we know
  193. they aren't needed.</P>
  194.  
  195.  
  196. <H3>Class Management / Interface</H3>
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203. <H2><A NAME="dl-functions"></A> <A NAME="ss8.3">8.3 Writing Builtin Functions </A></H2>
  204.  
  205.  
  206.  
  207.  
  208. <H3>Introduction</H3>
  209.  
  210.  
  211. <P>This section describes the process for building and linking your
  212. own function(s) into RLaB. There are two ways to do this: </P>
  213. <P>
  214. <OL>
  215. <LI> Compile and link your function with the rlab source to
  216. build a new executable. 
  217. </LI>
  218. <LI> Compile your function as a separate shared-object, and
  219. dynamically  link it with rlab using the <CODE>dlopen</CODE>
  220. function. Assuming your platform properly supports runtime
  221. dynamic linking.</LI>
  222. </OL>
  223. </P>
  224. <P>Either method requires that you write an interface function so that
  225. your function can communicate arguments and a return value with
  226. rlab. The interface function is the same whether you compile your
  227. function with rlab to make a new executable or compile your function
  228. as a shared object.  The end result of this process is the
  229. incorporation of your function into rlab as a builtin function.</P>
  230. <P>This subject will be presented almost entirely with
  231. examples. Writing builting functions is <EM>not</EM> difficult</P>
  232.  
  233.  
  234.  
  235. <H3>Example 1</H3>
  236.  
  237.  
  238. <P>All builtin functions are functions, which return an entity pointer,
  239. and have the same argument list. The following exampes is a trivial,
  240. but simple builtin function that multiplies its argument by 2, and
  241. returns the result. The basic steps in this (and most) function are:</P>
  242. <P>
  243. <OL>
  244. <LI> Perform argument checking. The interpreter does not perform
  245. any argument checking. Argument checking is entirely up to
  246. the builtin function. In this example argument checking
  247. consists of checking the number of arguments.
  248. </LI>
  249. <LI> Extracting the required data from the arguments list.
  250. </LI>
  251. <LI> Performing the desired operations.
  252. </LI>
  253. <LI> Creating and configuring the return entity.</LI>
  254. </OL>
  255. </P>
  256. <P>
  257. <HR>
  258. <PRE>
  259.   1: /* simplest.c: A simple builtin function example. */
  260.   2: 
  261.   3: /*
  262.   4:    Compile this file with (in this directory):
  263.   5:    cc -fPIC -c simplest.c -I../../ -I../../gc
  264.   6: */
  265.   7: 
  266.   8: /* Necessary header files. */
  267.   9: #include "rlab.h"
  268.  10: #include "ent.h"
  269.  11: #include "class.h"
  270.  12: #include "mem.h"
  271.  13: #include "bltin.h"
  272.  14: #include "util.h"
  273.  15: 
  274.  16: #include <stdio.h>
  275.  17: #include <string.h>
  276.  18: 
  277.  19: Ent *
  278.  20: Simplest (int nargs, Datum args[])
  279.  21: {
  280.  22:   double dtmp;
  281.  23:   Ent *e, *rent;
  282.  24:   MDR *m;
  283.  25: 
  284.  26:   /* Check the number of arguments. */
  285.  27:   if (nargs != 1)
  286.  28:   {
  287.  29:     rerror ("simplest: only 1 argument allowed");
  288.  30:   }
  289.  31: 
  290.  32:   /* Get the first (only) argument. */
  291.  33:   e = bltin_get_ent (args[0]);
  292.  34: 
  293.  35:   /* Perform the simplest operation. */
  294.  36:   dtmp = 2.0 * class_double (e);
  295.  37: 
  296.  38:   /* Create a new matrix containing the result. */
  297.  39:   m = mdr_CreateScalar (dtmp);
  298.  40: 
  299.  41:   /* Create the return entity. */
  300.  42:   rent = ent_Create ();
  301.  43: 
  302.  44:   /* Set the entity's data. */
  303.  45:   ent_data (rent) = m;
  304.  46: 
  305.  47:   /* Set the entity's data type. */
  306.  48:   ent_type (rent) = MATRIX_DENSE_REAL;
  307.  49: 
  308.  50:   /* Clean up the argument if possible. */
  309.  51:   ent_Clean (e);
  310.  52: 
  311.  53:   return (rent);
  312.  54: }
  313. </PRE>
  314. <HR>
  315. </P>
  316. <P>Now we will examine this function in more detail:</P>
  317. <P>
  318. <DL>
  319. <DT><B> Lines 1-17 </B><DD><P>Comments and header files.</P>
  320. <DT><B> Lines 19-24 </B><DD><P>The function and automatic variables
  321. declarations. <CODE>nargs</CODE> is the number of arguments the
  322. function was invoked with. <CODE>args</CODE> is the array of Datums
  323. that contains each argument.</P>
  324. <DT><B> Lines 26-30</B><DD><P>Checking the function argument(s). In this
  325. case we merely check that the function was called with only
  326. one argument. In some instances you might wish to do more, or
  327. less. </P>
  328. <DT><B> Line 33</B><DD><P>The function argument is extraced from the array
  329. of Datums. <CODE>bltin_get_ent</CODE> takes a single Datum, and
  330. converts (reduces) it to an entity.</P>
  331. <DT><B> Line 36</B><DD><P><CODE>class_double</CODE> takes a single entity as an
  332. argument, and returns a double value. If the argument to
  333. <CODE>class_double</CODE> is not recognized, and error message is
  334. created, and program control returns to the interpreter.</P>
  335. <P>The return value from <CODE>class_double</CODE> is multiplied by 2.</P>
  336. <DT><B> Line 39</B><DD><P>The return matrix is created, and its value is
  337. set to two.</P>
  338. <DT><B> Line 42</B><DD><P>The return entity (which will carry the return
  339. matrix) is created.</P>
  340. <DT><B> Line 45</B><DD><P>The return entity's data pointer is set to point
  341. at the return matrix.</P>
  342. <DT><B> Line 49</B><DD><P>The return entity's data type is set. The
  343. available types are listed at the bottom of <CODE>rlab.h</CODE>.</P>
  344. <DT><B> Line 51</B><DD><P>The argument entity is cleaned (the memory is
  345. free'ed) if possible.</P>
  346. </DL>
  347. </P>
  348. <P>The new builtin can be compiled on a Linux/ELF system like:</P>
  349. <P>
  350. <BLOCKQUOTE><CODE>
  351. <PRE>
  352. examples> gcc -fPIC -g -c simplest.c -I../../ -I../../gc
  353. examples> gcc -shared -o simplest.so  simplest.o
  354. </PRE>
  355. </CODE></BLOCKQUOTE>
  356. </P>
  357. <P>And tested like:</P>
  358. <P>
  359. <BLOCKQUOTE><CODE>
  360. <PRE>
  361. examples> ../../rlab -rmp
  362. > simplest = dlopen("./simplest.so", "Simplest")
  363.         <bltin-function>
  364. > i = 0;
  365. > while (i < 10000) { x=simplest(i); i++; }
  366. > i
  367.     1e+04  
  368. > x
  369.     2e+04  
  370. </PRE>
  371. </CODE></BLOCKQUOTE>
  372. </P>
  373.  
  374.  
  375.  
  376. <H3>Example 2, Portable Gray Map File I/O</H3>
  377.  
  378.  
  379. <P>This example may be a little more meaningful than the last. The file
  380. <CODE>pgm.c</CODE> contains builtin functions for loading and saving
  381. Portable Gray May (PGM) files. The <CODE>RSavepgm</CODE> function takes a
  382. real matrix, and writes it to a file using the PGM
  383. format. <CODE>RLoadpgm</CODE> reads a PGM files, and returns a matrix of
  384. the pixel values. An outline of the these functions follows:</P>
  385. <P>For <CODE>RSavepgm</CODE>:</P>
  386. <P>
  387. <OL>
  388. <LI> Check the number of arguments. Two or three arguments allowed.
  389. <OL>
  390. <LI> Image-Matrix. The matrix of pixel values.</LI>
  391. <LI> File-Name. The file to write.</LI>
  392. <LI> Maximum-Gray-Level. </LI>
  393. </OL>
  394. </LI>
  395. <LI> Get each of the arguments.</LI>
  396. <LI> Open the specified file for binary-write.</LI>
  397. <LI> Use the PGM API to write the matrix as a PGM-file.</LI>
  398. <LI> Clean up, and return.</LI>
  399. </OL>
  400. </P>
  401. <P>There are several sections of code that warrant explanation:</P>
  402. <P>
  403. <DL>
  404. <DT><B> Lines 53-71</B><DD><P>Here is where the arguments are extracted
  405. from the <CODE>args</CODE> array. The function <CODE>bltin_get_ent</CODE>
  406. is used extensively, as before. However, this time,
  407. <CODE>class_matrix_rea</CODE>, and <CODE>class_char_pointer</CODE> are
  408. used in addition to <CODE>class_double</CODE>.</P>
  409. <DT><B> Lines 73-88</B><DD><P>Here is a nice example of file I/O. The
  410. functions <CODE>get_file_ds</CODE>, and <CODE>close_file_ds</CODE>, are
  411. Rlab's interface to file I/O. In this instance a simple file
  412. is opened for writing. But, <CODE>get_file_ds</CODE> works equally
  413. well with sub-processes.</P>
  414. <DT><B> Lines 146, 147</B><DD><P>It is not necessary to use the function
  415. <CODE>ent_clean</CODE> since Rlab uses a generational garbage
  416. collector. However, using <CODE>ent_clean</CODE> can help in some
  417. cases, so it is a good idea to use it whenever possible.</P>
  418. <DT><B> Lines 152-155</B><DD><P>This is where the return-value entity is
  419. created, and configured. In this instance a scalar success
  420. value is all that is returned. </P>
  421. <DT><B> Lines 235-238</B><DD><P><CODE>RLoadpgm</CODE> returns a matrix. Note
  422. that the return entity configuration is similar to that in
  423. <CODE>RSavepgm</CODE>.</P>
  424. </DL>
  425. </P>
  426. <P>
  427. <HR>
  428. <PRE>
  429.   1: /* **************************************************************
  430.   2:  * pgm.c: Routines to load and save a matrix containing the pixels 
  431.   3:  *        of a gray scale image to or from a Portable Gray Map 
  432.   4:  *        file, using the libpgm library from the netpbm 
  433.   5:  *        distribution.
  434.   6:  *
  435.   7:  * To compile on a Linux/ELF system:
  436.   8:  *        gcc -g -fPIC -c pgm.c -I../../ -I../../gc
  437.   9:  *        gcc -shared -o pgm.so pgm.o -lpgm -lpbm 
  438.  10:  * ************************************************************** */
  439.  11: 
  440.  12: #include "rlab.h"
  441.  13: #include "ent.h"
  442.  14: #include "class.h"
  443.  15: #include "mem.h"
  444.  16: #include "bltin.h"
  445.  17: #include "rfileio.h"
  446.  18: #include "util.h"
  447.  19: 
  448.  20: #include <stdio.h>
  449.  21: #include <string.h>
  450.  22: #include <errno.h>
  451.  23: #include <math.h>
  452.  24: 
  453.  25: #include "pgm.h"
  454.  26: 
  455.  27: /* **************************************************************
  456.  28:  * RSavepgm: Save a PGM matrix to a file.
  457.  29: 
  458.  30:  * savepgm ( img_matrix, file_name, maximum_gray_level )
  459.  31:  * ************************************************************** */
  460.  32: 
  461.  33: Ent *
  462.  34: RSavepgm (int nargs, Datum args[])
  463.  35: {
  464.  36:   int gl, max_gl = 0, i, j;
  465.  37:   char *string; 
  466.  38:   double dgl;
  467.  39:   FILE *fn;
  468.  40:   Ent *FN, *GL, *IMG, *rent;
  469.  41:   MDR *img;
  470.  42:   gray **new;
  471.  43:   gray *row_new;
  472.  44: 
  473.  45:   char *kluge_argv[1];        /* we need to provide the pgm lib a dummy argv */
  474.  46: 
  475.  47:   kluge_argv[0]="savepgm"; /* initialize the dummy argv */
  476.  48: 
  477.  49:   /* Check nargs */
  478.  50:   if ((nargs < 2) || (nargs > 3))
  479.  51:     rerror ("savepgm: requires 2 or 3 arguments");
  480.  52: 
  481.  53:   /* Get the image. */
  482.  54:   /* First the image entity. */
  483.  55:   IMG = bltin_get_ent (args[0]);
  484.  56: 
  485.  57:   /* Next, get the image matrix from within the entity. */
  486.  58:   img = class_matrix_real (IMG);
  487.  59: 
  488.  60:   /* Then the filename for output. */
  489.  61:   FN = bltin_get_ent (args[1]);
  490.  62:   string = class_char_pointer (FN);
  491.  63: 
  492.  64:   /* If the third argument is present, get it for use as the maximum gray level */
  493.  65:   gl = -1;
  494.  66:   if (nargs == 3)
  495.  67:   {
  496.  68:     GL = bltin_get_ent (args[2]);
  497.  69:     dgl = class_double (GL);
  498.  70:     gl = dgl;
  499.  71:   }
  500.  72: 
  501.  73:   /* Open with file for binary write. */
  502.  74:   if ((fn = get_file_ds (string, "wb", 0)) == 0) 
  503.  75:   {
  504.  76:     fprintf (stderr, "savepgm: %s: cannot open for write\n", string);
  505.  77: 
  506.  78:     /* Clean up the arguments when we error out. */
  507.  79:     ent_Clean (IMG);
  508.  80:     ent_Clean (FN);
  509.  81:     if (nargs == 3) ent_Clean (GL);
  510.  82: 
  511.  83:     /* Return 0 to indicate failure. */
  512.  84:     rent = ent_Create ();
  513.  85:     ent_data (rent) = mdr_CreateScalar (0.0);
  514.  86:     ent_type (rent) = MATRIX_DENSE_REAL;
  515.  87:     return (rent);
  516.  88:   }
  517.  89: 
  518.  90:   /*
  519.  91:    * First we need to call pgm_init to initialize the pgm library.  
  520.  92:    * Normally this is called with argc and argv, but here we want to
  521.  93:    * just dummy it up.
  522.  94:    */
  523.  95:   i=1;
  524.  96:   pgm_init (&i, kluge_argv); 
  525.  97: 
  526.  98:   /* Allocate a PGM image array of the correct size */
  527.  99:   new = pgm_allocarray (MNC (img), MNR (img));
  528. 100: 
  529. 101:   /*
  530. 102:    * Now for each row of the image we want to store the pixel values
  531. 103:    * for each column.  Of course PGM differs from RLaB in the choice
  532. 104:    * of column-major and row-major order.
  533. 105:    */
  534. 106: 
  535. 107:   for (j = 0; j < MNR (img);j++)
  536. 108:   {
  537. 109:     row_new = *(new+j);
  538. 110:     for (i = 0; i < MNC (img); i++)
  539. 111:     {
  540. 112:       *(row_new+i) = (gray) MdrV0 (img, i*MNR(img)+j);
  541. 113: 
  542. 114:       /* Keep track of the maximum pixel value in the image */
  543. 115:       if(*(row_new+i) > max_gl)
  544. 116:       {
  545. 117:    max_gl=*(row_new+i);
  546. 118:       }
  547. 119:     }
  548. 120:   } 
  549. 121:   
  550. 122:   /*
  551. 123:    * If no maximum gray level was given as an argument, use the maximum
  552. 124:    * pixel value detected above. If the detected maximum pixel value is
  553. 125:    * greater than the one specified in argument 3, give a warning, and use
  554. 126:    * the maximum detected value.
  555. 127:    */
  556. 128: 
  557. 129:   if(gl == -1)
  558. 130:   {
  559. 131:     gl = max_gl;
  560. 132:   }
  561. 133:   else if(max_gl > gl)
  562. 134:   {
  563. 135:     fprintf (stderr,
  564. 136:         "savepgm: image contains pixel values greater than specified maximum");
  565. 137:     fprintf (stderr, "\nusing maximum pixel value instead\n");
  566. 138:     gl = max_gl;
  567. 139:   }
  568. 140: 
  569. 141:   /* Now the array new contains the PGM image, so write it out */
  570. 142:   pgm_writepgm (fn, new, MNC (img), MNR (img),(gray)gl, 0);
  571. 143:   pgm_freearray (new, MNR (img));
  572. 144:   
  573. 145:   /* Clean up before returning. */
  574. 146:   ent_Clean (FN);
  575. 147:   ent_Clean (IMG);
  576. 148:   if (nargs == 3) ent_Clean (GL);
  577. 149:   close_file_ds (string);
  578. 150:   
  579. 151:   /* Everything OK, return 1 to indicate success. */
  580. 152:   rent = ent_Create ();
  581. 153:   ent_data (rent) = mdr_CreateScalar (1.0);
  582. 154:   ent_type (rent) = MATRIX_DENSE_REAL;
  583. 155:   return (rent);
  584. 156: }
  585. 157: 
  586. 158: /* **************************************************************
  587. 159:  * RLavepgm: Load a PGM into a matrix.
  588. 160: 
  589. 161:  * loadpgm ( file_name )
  590. 162:  * ************************************************************** */
  591. 163: 
  592. 164: Ent *
  593. 165: RLoadpgm (int nargs, Datum args[])
  594. 166: {
  595. 167:   int i, j, rows, cols;
  596. 168:   char *string;
  597. 169:   FILE *fn;
  598. 170:   Ent *FN, *rent;
  599. 171:   MDR *img;
  600. 172:   gray **new;
  601. 173:   gray *row_new;
  602. 174:   gray gl;
  603. 175:   char *kluge_argv[1];     /* we need to provide the pgm lib a dummy argv */
  604. 176: 
  605. 177:   kluge_argv[0]="savepgm"; /* initialize the dummy argv */
  606. 178: 
  607. 179:   /* Check nargs */
  608. 180:   if (nargs != 1)
  609. 181:     rerror ("loadpgm: requires 1 argument");
  610. 182: 
  611. 183:   /* The the filename for input. */
  612. 184:   FN = bltin_get_ent (args[0]);
  613. 185:   string = class_char_pointer (FN);
  614. 186: 
  615. 187:   /* Open with file for binary read. */
  616. 188:   if ((fn = get_file_ds (string, "rb", 0)) == 0) 
  617. 189:   {
  618. 190:     fprintf (stderr, "loadpgm: %s: cannot open for write\n", string);
  619. 191: 
  620. 192:     /* Clean up the arguments when we error out. */
  621. 193:     ent_Clean (FN);
  622. 194: 
  623. 195:     /* Return 0 to indicate failure. */
  624. 196:     rent = ent_Create ();
  625. 197:     ent_data (rent) = mdr_CreateScalar (0.0);
  626. 198:     ent_type (rent) = MATRIX_DENSE_REAL;
  627. 199:     return (rent);
  628. 200:   } 
  629. 201: 
  630. 202:   /*
  631. 203:    * First we need to call pgm_init to initialize the pgm library.  
  632. 204:    * Normally this is called with argc and argv, but here we want to
  633. 205:    * just dummy it up.
  634. 206:    */
  635. 207: 
  636. 208:   i = 1;
  637. 209:   pgm_init (&i, kluge_argv); 
  638. 210: 
  639. 211:   /* Allocate a PGM image array of the correct size */
  640. 212:   new = pgm_readpgm (fn, &cols, &rows, &gl);
  641. 213:   img = mdr_Create (rows, cols);
  642. 214: 
  643. 215:   /*
  644. 216:    * Now for each row of the image we want to store the pixel values
  645. 217:    * for each column.  Of course PGM differs from RLaB in the choice
  646. 218:    * of column-major and row-major order.
  647. 219:    */
  648. 220:   for (j = 0; j < rows;j++)
  649. 221:   {
  650. 222:     row_new = *(new+j);
  651. 223:     for (i = 0; i < cols; i++)
  652. 224:     {
  653. 225:        MdrV0 (img, i*MNR(img)+j) = *(row_new+i);
  654. 226:     }
  655. 227:   }  
  656. 228: 
  657. 229:   /* Clean up before returning. */
  658. 230:   pgm_freearray(new, MNR (img));
  659. 231:   ent_Clean (FN);
  660. 232:   close_file_ds (string);
  661. 233:   
  662. 234:   /* Everything OK, return the image. */
  663. 235:   rent = ent_Create ();
  664. 236:   ent_data (rent) = img;
  665. 237:   ent_type (rent) = MATRIX_DENSE_REAL;
  666. 238:   return (rent);
  667. 239: }
  668. </PRE>
  669. <HR>
  670. </P>
  671. <P>A simple example showing one possible usage of these two new builtin
  672. functions is provided. Both <CODE>savepgm</CODE>, and <CODE>loadpgm</CODE> are
  673. created via the <CODE>dlopen</CODE> function. The Linux logo is read in,
  674. and some white-noise is added to the picture. The new graphic is
  675. written to a file, which can then be viewed with any PGM compatible
  676. viewer (xv for example).</P>
  677. <P>
  678. <BLOCKQUOTE><CODE>
  679. <PRE>
  680. examples> ../../rlab -mpr
  681. > savepgm = dlopen("./pgm.so","RSavepgm")
  682.         <bltin-function>
  683. > loadpgm = dlopen("./pgm.so","RLoadpgm")
  684.         <bltin-function>
  685. > logo = loadpgm("Logo.pgm");
  686. > show(logo);
  687.         nr                  :   303
  688.         nc                  :   257
  689.         n                   :   77871
  690.         class               :   num
  691.         type                :   real
  692.         storage             :   dense
  693. > max(max(logo))
  694.       248  
  695. > min(min(logo))
  696.         0  
  697. > rand("uniform", 0,50);
  698. > logo = logo + rand(size(logo));
  699. > savepgm(logo,"Logo_noisy.pgm");
  700. > close("Logo_noisy.pgm");
  701. </PRE>
  702. </CODE></BLOCKQUOTE>
  703. </P>
  704.  
  705.  
  706.  
  707. <H3>Dynamic Linking</H3>
  708.  
  709.  
  710. <P><B> Not Finished Yet ! </B></P>
  711.  
  712.  
  713.  
  714.  
  715. <HR>
  716. <A HREF="rlab-ref-7.html"><IMG SRC="prev.gif" ALT="Previous"></A>
  717. <A HREF="rlab-ref-9.html"><IMG SRC="next.gif" ALT="Next"></A>
  718. <A HREF="rlab-ref.html#toc8"><IMG SRC="toc.gif" ALT="Contents"></A>
  719. </BODY>
  720. </HTML>
  721.