|
|
1.1 root 1: #ifndef lint
2: static char RCSid[] = "$Header: procedures.c,v 2.2 86/11/11 09:49:06 jqj Exp $";
3: #endif
4:
5: /* $Log: procedures.c,v $
6: * Revision 2.2 86/11/11 09:49:06 jqj
7: * Per Ed Flint, if a Courier procedure returns void, the server should still
8: * do a SendReturnMessage(0,0), so generate the proper code for this case.
9: * Note that this eventually implies (in xnslib/readwrite.c) that a writev()
10: * has an iovec with 0 length, which might tickle a kernel bug in some
11: * implementations.
12: *
13: * Revision 2.1 86/06/06 07:28:49 jqj
14: * many mods for better symbol table management: added CurrentModule,
15: * made check_dependency, make_symbol, check_def set/use/use a symbol
16: * table instead of a module name string, etc. Result is that we can
17: * now handle DEPENDS UPON 2 versions of same program.
18: *
19: * Revision 2.0 85/11/21 07:21:43 jqj
20: * 4.3BSD standard release
21: *
22: * Revision 1.5 85/05/06 08:13:31 jqj
23: * *** empty log message ***
24: *
25: * Revision 1.5 85/05/06 08:13:31 jqj
26: * Almost Beta-test version.
27: *
28: * Revision 1.4 85/03/26 06:10:21 jqj
29: * Revised public alpha-test version, released 26 March 1985
30: *
31: * Revision 1.3 85/03/11 16:39:55 jqj
32: * Public alpha-test version, released 11 March 1985
33: *
34: * Revision 1.2 85/02/21 11:05:39 jqj
35: * alpha test version
36: *
37: * Revision 1.1 85/02/15 13:55:36 jqj
38: * Initial revision
39: *
40: */
41:
42: #define argname(p) ((char *) car(caar(p)))
43: #define argtype(p) ((struct type *) cdar(p))
44:
45: /*
46: * routines for generating procedures and errors
47: */
48:
49: #include "compiler.h"
50:
51: /*
52: * Generate client and server functions for procedure declarations.
53: */
54: define_procedure_constant(symbol,typtr,value)
55: struct object *symbol;
56: struct type *typtr;
57: struct constant *value;
58: {
59: struct type *resulttype;
60: char *procvalue;
61: char * resultname;
62: char buf[MAXSTR];
63: list p, q;
64:
65: if (recursive_flag) /* don't bother to do anything for procs */
66: return; /* in DEPENDS UPON modules */
67: if (typtr->type_constr != C_PROCEDURE)
68: error(FATAL, "internal error (define_procedure): not a procedure");
69: if (value->cn_constr != C_NUMERIC) {
70: error(ERROR,"Values of procedure constants must be numeric");
71: procvalue = "-1";
72: }
73: else
74: procvalue = value->cn_value;
75: /*
76: * RETURNS stuff: coerce the result to be a single record
77: */
78: if (length(typtr->type_results) > 0) {
79: struct object *resultobj;
80:
81: resulttype = record_type(typtr->type_results);
82: sprintf(buf,"%sResults",name_of(symbol));
83: resultname = copy(buf);
84: resultobj = make_symbol(resultname,CurrentModule);
85: define_type(resultobj, resulttype);
86: /* replaces define_record_type(resulttype); */
87: typtr->type_results = cons( cons( cons((list)resultname, NIL),
88: (list)resulttype),
89: NIL);
90: }
91: /*
92: * REPORTS stuff: check here to make sure the errors are all defined
93: */
94: for (p = typtr->type_errors, q = NIL; p != NIL; q = p, p = cdr(p)) {
95: struct object *sym;
96: sym = check_def((char *)car(p),CurrentModule);
97: if (sym == (struct object *)0) {
98: error(ERROR,"Error constant %s not defined",
99: (char*)car(p));
100: if (q == NIL) typtr->type_errors = cdr(p);
101: else cdr(q) = cdr(p);
102: }
103: else if (sym->o_class != O_CONSTANT
104: || sym->o_constant->cn_constr != C_ERROR) {
105: error(ERROR,"Symbol %s is not of appropriate type",
106: name_of(sym));
107: if (q == NIL) typtr->type_errors = cdr(p);
108: else cdr(q) = cdr(p);
109: }
110: }
111: /*
112: * Argument stuff: make sure all the argument types are defined
113: */
114: for (p = typtr->type_args; p != NIL; p = cdr(p)) {
115: if (typename(argtype(p)) == NULL) {
116: struct object *name;
117: name = make_symbol(gensym("T_p"),CurrentModule);
118: define_type(name,argtype(p));
119: }
120: }
121: /*
122: * Actually generate code for this procedure
123: */
124: proc_functions(symbol->o_constant->cn_name, typtr, procvalue);
125: /*
126: * Save this procedure on the global procs for wrapup (server
127: * dispatch code)
128: */
129: Procedures = cons(cons( (list)symbol->o_constant->cn_name,
130: (list)procvalue ),
131: Procedures);
132: }
133:
134:
135: /*
136: * Generate funcions for client and server calls to a procedure.
137: */
138: proc_functions(proc_name, type, proc_number)
139: char *proc_name;
140: struct type *type;
141: char *proc_number;
142: {
143: list p;
144: int nresults, fixed_size, variable_size;
145: struct type *t, *bt, *result_type;
146: char *result_name, *ref, *rtname;
147:
148: /*
149: * Make sure there is at most one result returned.
150: */
151: nresults = length(type->type_results);
152: if (nresults > 1) {
153: error(ERROR, "procedures that return multiple results are not supported");
154: return;
155: }
156: if (nresults) {
157: result_name = "_Results";
158: result_type = argtype(type->type_results);
159: rtname = typename(result_type);
160: } else {
161: rtname = "void";
162: }
163:
164: /*
165: * Server routine.
166: */
167:
168: fprintf(server, "\nextern %s %s();\n", rtname, proc_name);
169: fprintf(server,
170: "\nserver_%s(_buf)\n\
171: \tregister Unspecified *_buf;\n\
172: {\n\
173: \tregister Unspecified *_bp = _buf;\n\
174: \tregister LongCardinal _n;\n",
175: proc_name);
176: for (p = type->type_args; p != NIL; p = cdr(p)) {
177: t = argtype(p);
178: fprintf(server, "\t%s %s;\n", typename(t), argname(p));
179: }
180: if (nresults)
181: fprintf(server, "\t%s %s;\n", rtname, result_name);
182: fprintf(server, "\n");
183: /*
184: * Generate code to internalize the arguments.
185: */
186: for (p = type->type_args; p != NIL; p = cdr(p)) {
187: t = argtype(p);
188: ref = refstr(t);
189: fprintf(server, "\t_bp += %s(%s%s, _bp);\n",
190: xfn(INTERNALIZE, t), ref, argname(p));
191: }
192: /*
193: * Generate code to call the procedure.
194: */
195: if (nresults)
196: fprintf(server, "\t%s = %s(_serverConnection, 0",
197: result_name, proc_name);
198: else
199: fprintf(server, "\t%s(_serverConnection, 0", proc_name);
200: for (p = type->type_args; p != NIL; p = cdr(p)) {
201: fprintf(server, ", %s", argname(p));
202: }
203: fprintf(server, ");\n");
204: /*
205: * Generate code to externalize the result.
206: */
207: if (nresults) {
208: ref = refstr(result_type);
209: fprintf(server,
210: "\t_n = sizeof_%s(%s%s);\n\
211: \t_bp = Allocate(_n);\n\
212: \t%s(%s%s, _bp);\n\
213: \tSendReturnMessage(_n, _bp);\n\
214: \tDeallocate(_bp);\n\
215: }\n",
216: rtname, ref, result_name,
217: xfn(EXTERNALIZE, result_type), ref, result_name);
218: } else
219: fprintf(server,
220: "\tSendReturnMessage( 0, _bp);\n\
221: }\n"
222: );
223:
224: /*
225: * Stub routine for client.
226: */
227:
228: fprintf(header, "\nextern %s %s();\n",
229: rtname, proc_name);
230: fprintf(client,
231: "\n\
232: %s\n\
233: %s(_Connection, _BDTprocptr",
234: rtname, proc_name);
235: for (p = type->type_args; p != NIL; p = cdr(p))
236: fprintf(client, ", %s", argname(p));
237: fprintf(client, ")\n\
238: \tCourierConnection *_Connection;\n\
239: \tint (*_BDTprocptr)();\n\
240: "
241: );
242: for (p = type->type_args; p != NIL; p = cdr(p)) {
243: t = argtype(p);
244: fprintf(client, "\t%s %s;\n", typename(t), argname(p));
245: }
246: fprintf(client, "{\n");
247: if (nresults)
248: fprintf(client, "\t%s %s;\n", rtname, result_name);
249: fprintf(client,
250: "\tregister Unspecified *_buf, *_bp;\n\
251: \tBoolean _errorflag;\n\
252: \tCardinal _errtype;\n"
253: );
254: /*
255: * Determine the size of the arguments.
256: * This is like the code in record_type().
257: */
258: fixed_size = 0;
259: variable_size = 0;
260: for (p = type->type_args; p != NIL; p = cdr(p)) {
261: bt = argtype(p);
262: if (bt->type_xsize == -1) {
263: variable_size = 1;
264: } else {
265: fixed_size += bt->type_xsize;
266: }
267: }
268: if (!variable_size) {
269: /*
270: * The argument list is fixed-size.
271: */
272: fprintf(client,
273: "\n\
274: \t_buf = Allocate(%d);\n",
275: fixed_size);
276: } else {
277: /*
278: * There are some variable-size arguments.
279: */
280: fprintf(client,
281: "\tregister LongCardinal _n = %d;\n\
282: \n",
283: fixed_size);
284: for (p = type->type_args; p != NIL; p = cdr(p)) {
285: t = argtype(p);
286: bt = t;
287: if (bt->type_xsize != -1)
288: continue;
289: ref = refstr(bt);
290: fprintf(client,
291: "\t_n += sizeof_%s(%s%s);\n",
292: typename(t), ref, argname(p));
293: }
294: fprintf(client,
295: "\t_buf = Allocate(_n);\n"
296: );
297: }
298: fprintf(client,
299: "\t_bp = _buf;\n"
300: );
301: /*
302: * Generate code to externalize the arguments.
303: */
304: for (p = type->type_args; p != NIL; p = cdr(p)) {
305: t = argtype(p);
306: ref = refstr(t);
307: fprintf(client, "\t_bp += %s(%s%s, _bp);\n",
308: xfn(EXTERNALIZE, t), ref, argname(p));
309: }
310: if (!variable_size) {
311: fprintf(client,
312: "\tSendCallMessage(_Connection, %d, %d, %s, %d, _buf);\n",
313: CurrentNumber, CurrentVersion,
314: proc_number, fixed_size);
315: } else {
316: fprintf(client,
317: "\tSendCallMessage(_Connection, %d, %d, %s, _n, _buf);\n",
318: CurrentNumber, CurrentVersion,
319: proc_number);
320: }
321: fprintf(client,
322: "\tDeallocate(_buf);\n\
323: \tMaybeCallBDTHandler(_Connection, _BDTprocptr);\n"
324: );
325: /*
326: * Generate code to receive the results and interpret them
327: * as errors
328: */
329: fprintf(client,
330: "\t_bp = ReceiveReturnMessage(_Connection, &_errorflag);\n\
331: \t_buf = _bp;\n\
332: \tif (_errorflag) {\n\
333: \t\t_bp += %s(&_errtype, _bp);\n\
334: \t\tswitch (ERROR_OFFSET+_errtype) {\n",
335: xfn(INTERNALIZE, Cardinal_type)
336: );
337: for (p = type->type_errors; p != NIL; p = cdr(p)) {
338: struct constant *errconst;
339: struct type *errtype;
340: errconst = (check_def((char *)car(p),CurrentModule))->o_constant;
341: errtype = (struct type *) cdr(errconst->cn_list);
342: if (errtype == TNIL)
343: fprintf(client,
344: "\t\tcase %s:\n\
345: \t\t\traise(ERROR_OFFSET+_errtype, 0);\n\
346: \t\t\t/*NOTREACHED*/\n",
347: errconst->cn_name);
348: else
349: fprintf(client,
350: "\t\tcase %s: {\n\
351: \t\t\tstatic %s _result;\n\
352: \t\t\t_bp += %s(%s_result, _bp);\n\
353: \t\t\traise(ERROR_OFFSET+_errtype, (char *) &_result);\n\
354: \t\t\t/*NOTREACHED*/\n\
355: \t\t\t}\n",
356: errconst->cn_name,
357: typename(errtype),
358: xfn(INTERNALIZE, errtype), refstr(errtype)
359: );
360: }
361: fprintf(client,
362: "\t\tdefault:\n\
363: \t\t\t/* don't know how to unpack this */\n\
364: \t\t\traise(ERROR_OFFSET+_errtype, 0);\n\
365: \t\t\t/*NOTREACHED*/\n\
366: \t\t}\n"
367: );
368: /*
369: * Code to unpack results and return
370: */
371: if (nresults)
372: fprintf(client,
373: "\t} else\n\
374: \t\t_bp += %s(%s%s, _bp);\n\
375: \tDeallocate(_buf);\n\
376: \treturn (%s);\n\
377: }\n",
378: xfn(INTERNALIZE, result_type),
379: refstr(result_type), result_name, result_name);
380: else
381: fprintf(client,
382: "\t}\n\
383: \tDeallocate(_buf);\n\
384: }\n");
385: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.