halcompile.g
1 #!/usr/bin/env python 2 # This is 'halcompile', a tool to write HAL boilerplate 3 # Copyright 2006 Jeff Epler <jepler@unpythonic.net> 4 # 5 # This program is free software; you can redistribute it and/or modify 6 # it under the terms of the GNU General Public License as published by 7 # the Free Software Foundation; either version 2 of the License, or 8 # (at your option) any later version. 9 # 10 # This program is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU General Public License for more details. 14 # 15 # You should have received a copy of the GNU General Public License 16 # along with this program; if not, write to the Free Software 17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 from __future__ import print_function 19 20 %% 21 parser Hal: 22 ignore: "//.*" 23 ignore: "/[*](.|\n)*?[*]/" 24 ignore: "[ \t\r\n]+" 25 26 token END: ";;" 27 token PARAMDIRECTION: "rw|r" 28 token PINDIRECTION: "in|out|io" 29 token TYPE: "float|bit|signed|unsigned|u32|s32" 30 token NAME: "[a-zA-Z_][a-zA-Z0-9_]*" 31 token STARREDNAME: "[*]*[a-zA-Z_][a-zA-Z0-9_]*" 32 token HALNAME: "[#a-zA-Z_][-#a-zA-Z0-9_.]*" 33 token FPNUMBER: "-?([0-9]*\.[0-9]+|[0-9]+\.?)([Ee][+-]?[0-9]+)?f?" 34 token NUMBER: "0x[0-9a-fA-F]+|[+-]?[0-9]+" 35 token STRING: "\"(\\.|[^\\\"])*\"" 36 token HEADER: "<.*?>" 37 token POP: "[-()+*/]|&&|\\|\\||personality|==|&|!=|<<|<|<=|>>|>|>=" 38 token TSTRING: "r?\"\"\"(\\.|\\\n|[^\\\"]|\"(?!\"\")|\n)*\"\"\"" 39 40 rule File: ComponentDeclaration Declaration* "$" {{ return True }} 41 rule ComponentDeclaration: 42 "component" NAME OptString";" {{ comp(NAME, OptString); }} 43 rule Declaration: 44 "pin" PINDIRECTION TYPE HALNAME OptArray OptSAssign OptPersonality OptString ";" {{ pin(HALNAME, TYPE, OptArray, PINDIRECTION, OptString, OptSAssign, OptPersonality) }} 45 | "param" PARAMDIRECTION TYPE HALNAME OptArray OptSAssign OptPersonality OptString ";" {{ param(HALNAME, TYPE, OptArray, PARAMDIRECTION, OptString, OptSAssign, OptPersonality) }} 46 | "function" NAME OptFP OptString ";" {{ function(NAME, OptFP, OptString) }} 47 | "variable" NAME STARREDNAME OptSimpleArray OptAssign ";" {{ variable(NAME, STARREDNAME, OptSimpleArray, OptAssign) }} 48 | "option" NAME OptValue ";" {{ option(NAME, OptValue) }} 49 | "see_also" String ";" {{ see_also(String) }} 50 | "notes" String ";" {{ notes(String) }} 51 | "description" String ";" {{ description(String) }} 52 | "license" String ";" {{ license(String) }} 53 | "author" String ";" {{ author(String) }} 54 | "include" Header ";" {{ include(Header) }} 55 | "modparam" NAME {{ NAME1=NAME; }} NAME OptSAssign OptString ";" {{ modparam(NAME1, NAME, OptSAssign, OptString) }} 56 57 rule Header: STRING {{ return STRING }} | HEADER {{ return HEADER }} 58 59 rule String: TSTRING {{ return eval(TSTRING) }} 60 | STRING {{ return eval(STRING) }} 61 62 rule OptPersonality: "if" Personality {{ return Personality }} 63 | {{ return None }} 64 rule Personality: {{ pp = [] }} (PersonalityPart {{ pp.append(PersonalityPart) }} )* {{ return " ".join(pp) }} 65 rule PersonalityPart: NUMBER {{ return NUMBER }} 66 | POP {{ return POP }} 67 rule OptSimpleArray: "\[" NUMBER "\]" {{ return int(NUMBER) }} 68 | {{ return 0 }} 69 rule OptArray: "\[" NUMBER OptArrayPersonality "\]" {{ return OptArrayPersonality and (int(NUMBER), OptArrayPersonality) or int(NUMBER) }} 70 | {{ return 0 }} 71 rule OptArrayPersonality: ":" Personality {{ return Personality }} 72 | {{ return None }} 73 rule OptString: TSTRING {{ return eval(TSTRING) }} 74 | STRING {{ return eval(STRING) }} 75 | {{ return '' }} 76 rule OptAssign: "=" Value {{ return Value; }} 77 | {{ return None }} 78 rule OptSAssign: "=" SValue {{ return SValue; }} 79 | {{ return None }} 80 rule OptFP: "fp" {{ return 1 }} | "nofp" {{ return 0 }} | {{ return 1 }} 81 rule Value: "yes" {{ return 1 }} | "no" {{ return 0 }} 82 | "true" {{ return 1 }} | "false" {{ return 0 }} 83 | "TRUE" {{ return 1 }} | "FALSE" {{ return 0 }} 84 | NAME {{ return NAME }} 85 | FPNUMBER {{ return float(FPNUMBER.rstrip("f")) }} 86 | NUMBER {{ return int(NUMBER,0) }} 87 rule SValue: "yes" {{ return "yes" }} | "no" {{ return "no" }} 88 | "true" {{ return "true" }} | "false" {{ return "false" }} 89 | "TRUE" {{ return "TRUE" }} | "FALSE" {{ return "FALSE" }} 90 | NAME {{ return NAME }} 91 | FPNUMBER {{ return FPNUMBER }} 92 | NUMBER {{ return NUMBER }} 93 rule OptValue: Value {{ return Value }} 94 | TSTRING {{ return eval(TSTRING) }} 95 | STRING {{ return eval(STRING) }} 96 | {{ return 1 }} 97 rule OptSValue: SValue {{ return SValue }} 98 | {{ return 1 }} 99 %% 100 101 import os, sys, tempfile, shutil, getopt, time 102 BASE = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "..")) 103 sys.path.insert(0, os.path.join(BASE, "lib", "python")) 104 105 MAX_USERSPACE_NAMES = 16 # for userspace (loadusr) components 106 # NOTE: names are assigned dynamically for realtime components (loadrt) 107 108 # Components that use 'personality' features statically allocate 109 # memory based on MAX_PERSONALITIES (RTAPI_MP_ARRAY_INT) 110 # The number can be set with the cmdline option -P|--personalities 111 # Smaller values may be useful since the index of the personality 112 # exported is computed modulo MAX_PERSONALITIES 113 MAX_PERSONALITIES = 64 114 115 mp_decl_map = {'int': 'RTAPI_MP_INT', 'dummy': None} 116 117 # These are symbols that comp puts in the global namespace of the C file it 118 # creates. The user is thus not allowed to add any symbols with these 119 # names. That includes not only global variables and functions, but also 120 # HAL pins & parameters, because comp adds #defines with the names of HAL 121 # pins & params. 122 reserved_names = [ 'comp_id', 'fperiod', 'rtapi_app_main', 'rtapi_app_exit', 'extra_setup', 'extra_cleanup' ] 123 124 def _parse(rule, text, filename=None): 125 global P, S 126 S = HalScanner(text, filename=filename) 127 P = Hal(S) 128 return runtime.wrap_error_reporter(P, rule) 129 130 def parse(filename): 131 initialize() 132 f = open(filename).read() 133 if '\r' in f: 134 if require_unix_line_endings: 135 raise SystemExit("%s:0: Error: File contains DOS-style or Mac-style line endings." % filename) 136 else: 137 print("%s:0: Warning: File contains DOS-style or Mac-style line endings." % filename, file=sys.stderr) 138 f = open(filename, "rU").read() 139 a, b = f.split("\n;;\n", 1) 140 p = _parse('File', a + "\n\n", filename) 141 if not p: raise SystemExit(1) 142 if require_license: 143 if not finddoc('license'): 144 raise SystemExit("%s:0: License not specified" % filename) 145 return a, b 146 147 dirmap = {'r': 'HAL_RO', 'rw': 'HAL_RW', 'in': 'HAL_IN', 'out': 'HAL_OUT', 'io': 'HAL_IO' } 148 typemap = {'signed': 's32', 'unsigned': 'u32'} 149 deprmap = {'s32': 'signed', 'u32': 'unsigned'} 150 deprecated = ['s32', 'u32'] 151 152 def initialize(): 153 global functions, params, pins, options, comp_name, names, docs, variables 154 global modparams, includes 155 156 functions = []; params = []; pins = []; options = {}; variables = [] 157 modparams = []; docs = []; includes = []; 158 comp_name = None 159 160 names = {} 161 162 def Warn(msg, *args): 163 if args: 164 msg = msg % args 165 print("%s:%d: Warning: %s" % (S.filename, S.line, msg), file=sys.stderr) 166 167 def Error(msg, *args): 168 if args: 169 msg = msg % args 170 raise runtime.SyntaxError(S.get_pos(), msg, None) 171 172 def comp(name, doc): 173 docs.append(('component', name, doc)) 174 global comp_name 175 if comp_name: 176 Error("Duplicate specification of component name") 177 comp_name = name; 178 179 def description(doc): 180 docs.append(('descr', doc)); 181 182 def license(doc): 183 docs.append(('license', doc)); 184 185 def author(doc): 186 docs.append(('author', doc)); 187 188 def see_also(doc): 189 docs.append(('see_also', doc)); 190 191 def notes(doc): 192 docs.append(('notes', doc)); 193 194 def type2type(type): 195 # When we start warning about s32/u32 this is where the warning goes 196 return typemap.get(type, type) 197 198 def checkarray(name, array): 199 hashes = len(re.findall("#+", name)) 200 if array: 201 if hashes == 0: Error("Array name contains no #: %r" % name) 202 if hashes > 1: Error("Array name contains more than one block of #: %r" % name) 203 else: 204 if hashes > 0: Error("Non-array name contains #: %r" % name) 205 206 def check_name_ok(name): 207 if name in reserved_names: 208 Error("Variable name %s is reserved" % name) 209 if name in names: 210 Error("Duplicate item name %s" % name) 211 212 def pin(name, type, array, dir, doc, value, personality): 213 checkarray(name, array) 214 type = type2type(type) 215 check_name_ok(name) 216 docs.append(('pin', name, type, array, dir, doc, value, personality)) 217 names[name] = None 218 pins.append((name, type, array, dir, value, personality)) 219 220 def param(name, type, array, dir, doc, value, personality): 221 checkarray(name, array) 222 type = type2type(type) 223 check_name_ok(name) 224 docs.append(('param', name, type, array, dir, doc, value, personality)) 225 names[name] = None 226 params.append((name, type, array, dir, value, personality)) 227 228 def function(name, fp, doc): 229 check_name_ok(name) 230 docs.append(('funct', name, fp, doc)) 231 names[name] = None 232 functions.append((name, fp)) 233 234 def option(name, value): 235 if name in options: 236 Error("Duplicate option name %s" % name) 237 options[name] = value 238 239 def variable(type, name, array, default): 240 check_name_ok(name) 241 names[name] = None 242 variables.append((type, name, array, default)) 243 244 def modparam(type, name, default, doc): 245 check_name_ok(name) 246 names[name] = None 247 modparams.append((type, name, default, doc)) 248 249 def include(value): 250 includes.append((value)) 251 252 def removeprefix(s,p): 253 if s.startswith(p): return s[len(p):] 254 return s 255 256 def to_hal(name): 257 name = re.sub("#+", lambda m: "%%0%dd" % len(m.group(0)), name) 258 return name.replace("_", "-").rstrip("-").rstrip(".") 259 def to_c(name): 260 name = re.sub("[-._]*#+", "", name) 261 name = name.replace("#", "").replace(".", "_").replace("-", "_") 262 return re.sub("_+", "_", name) 263 264 def prologue(f): 265 print("/* Autogenerated by %s on %s -- do not edit */" % ( 266 sys.argv[0], time.asctime()), file=f) 267 print("""\ 268 #include "rtapi.h" 269 #ifdef RTAPI 270 #include "rtapi_app.h" 271 #endif 272 #include "rtapi_string.h" 273 #include "rtapi_errno.h" 274 #include "hal.h" 275 #include "rtapi_math64.h" 276 277 static int comp_id; 278 """, file=f) 279 for name in includes: 280 print("#include %s" % name, file=f) 281 282 names = {} 283 284 def q(s): 285 s = s.replace("\\", "\\\\") 286 s = s.replace("\"", "\\\"") 287 s = s.replace("\r", "\\r") 288 s = s.replace("\n", "\\n") 289 s = s.replace("\t", "\\t") 290 s = s.replace("\v", "\\v") 291 return '"%s"' % s 292 293 print("#ifdef MODULE_INFO", file=f) 294 for v in docs: 295 if not v: continue 296 v = ":".join(map(str, v)) 297 print("MODULE_INFO(linuxcnc, %s);" % q(v), file=f) 298 license = finddoc('license') 299 if license and license[1]: 300 print("MODULE_LICENSE(\"%s\");" % license[1].split("\n")[0], file=f) 301 print("#endif // MODULE_INFO", file=f) 302 print("", file=f) 303 304 305 has_data = options.get("data") 306 307 has_array = False 308 has_personality = False 309 for name, type, array, dir, value, personality in pins: 310 if array: has_array = True 311 if isinstance(array, tuple): has_personality = True 312 if personality: has_personality = True 313 for name, type, array, dir, value, personality in params: 314 if array: has_array = True 315 if isinstance(array, tuple): has_personality = True 316 if personality: has_personality = True 317 for type, name, default, doc in modparams: 318 decl = mp_decl_map[type] 319 if decl: 320 print("%s %s" % (type, name), end=' ', file=f) 321 if default: print("= %s;" % default, file=f) 322 else: print(";", file=f) 323 print("%s(%s, %s);" % (decl, name, q(doc)), file=f) 324 325 print("", file=f) 326 print("struct __comp_state {", file=f) 327 print(" struct __comp_state *_next;", file=f) 328 if has_personality: 329 print(" int _personality;", file=f) 330 331 for name, type, array, dir, value, personality in pins: 332 if array: 333 if isinstance(array, tuple): array = array[0] 334 print(" hal_%s_t *%s[%s];" % (type, to_c(name), array), file=f) 335 else: 336 print(" hal_%s_t *%s;" % (type, to_c(name)), file=f) 337 names[name] = 1 338 339 for name, type, array, dir, value, personality in params: 340 if array: 341 if isinstance(array, tuple): array = array[0] 342 print(" hal_%s_t %s[%s];" % (type, to_c(name), array), file=f) 343 else: 344 print(" hal_%s_t %s;" % (type, to_c(name)), file=f) 345 names[name] = 1 346 347 for type, name, array, value in variables: 348 if array: 349 print(" %s %s[%d];\n" % (type, name, array), file=f) 350 else: 351 print(" %s %s;\n" % (type, name), file=f) 352 if has_data: 353 print(" void *_data;", file=f) 354 355 print("};", file=f) 356 357 if options.get("userspace"): 358 print("#include <stdlib.h>", file=f) 359 360 print("struct __comp_state *__comp_first_inst=0, *__comp_last_inst=0;", file=f) 361 362 print("", file=f) 363 for name, fp in functions: 364 if name in names: 365 Error("Duplicate item name: %s" % name) 366 print("static void %s(struct __comp_state *__comp_inst, long period);" % to_c(name), file=f) 367 names[name] = 1 368 369 print("static int __comp_get_data_size(void);", file=f) 370 if options.get("extra_setup"): 371 print("static int extra_setup(struct __comp_state *__comp_inst, char *prefix, long extra_arg);", file=f) 372 if options.get("extra_cleanup"): 373 print("static void extra_cleanup(void);", file=f) 374 375 if not options.get("no_convenience_defines"): 376 print("#undef TRUE", file=f) 377 print("#define TRUE (1)", file=f) 378 print("#undef FALSE", file=f) 379 print("#define FALSE (0)", file=f) 380 print("#undef true", file=f) 381 print("#define true (1)", file=f) 382 print("#undef false", file=f) 383 print("#define false (0)", file=f) 384 385 print("", file=f) 386 if has_personality: 387 print("static int export(char *prefix, long extra_arg, long personality) {", file=f) 388 else: 389 print("static int export(char *prefix, long extra_arg) {", file=f) 390 if len(functions) > 0: 391 print(" char buf[HAL_NAME_LEN + 1];", file=f) 392 print(" int r = 0;", file=f) 393 if has_array: 394 print(" int j = 0;", file=f) 395 print(" int sz = sizeof(struct __comp_state) + __comp_get_data_size();", file=f) 396 print(" struct __comp_state *inst = hal_malloc(sz);", file=f) 397 print(" memset(inst, 0, sz);", file=f) 398 if has_data: 399 print(" inst->_data = (char*)inst + sizeof(struct __comp_state);", file=f) 400 if has_personality: 401 print(" inst->_personality = personality;", file=f) 402 if options.get("extra_setup"): 403 print(" r = extra_setup(inst, prefix, extra_arg);", file=f) 404 print(" if(r != 0) return r;", file=f) 405 # the extra_setup() function may have changed the personality 406 if has_personality: 407 print(" personality = inst->_personality;", file=f) 408 for name, type, array, dir, value, personality in pins: 409 if personality: 410 print("if(%s) {" % personality, file=f) 411 if array: 412 if isinstance(array, tuple): 413 lim, cnt = array 414 print(" if((%s) > (%s)) {" % (cnt, lim), file=f) 415 print(' rtapi_print_msg(RTAPI_MSG_ERR,' \ 416 '"Pin %s: Requested size %%d exceeds max size %%d\\n",' 417 '(int)%s, (int)%s);' % (name, cnt, lim), file=f) 418 print(" return -ENOSPC;", file=f) 419 print(" }", file=f) 420 else: cnt = array 421 print(" for(j=0; j < (%s); j++) {" % cnt, file=f) 422 print(" r = hal_pin_%s_newf(%s, &(inst->%s[j]), comp_id," % ( 423 type, dirmap[dir], to_c(name)), file=f) 424 print(" \"%%s%s\", prefix, j);" % to_hal("." + name), file=f) 425 print(" if(r != 0) return r;", file=f) 426 if value is not None: 427 print(" *(inst->%s[j]) = %s;" % (to_c(name), value), file=f) 428 print(" }", file=f) 429 else: 430 print(" r = hal_pin_%s_newf(%s, &(inst->%s), comp_id," % ( 431 type, dirmap[dir], to_c(name)), file=f) 432 print(" \"%%s%s\", prefix);" % to_hal("." + name), file=f) 433 print(" if(r != 0) return r;", file=f) 434 if value is not None: 435 print(" *(inst->%s) = %s;" % (to_c(name), value), file=f) 436 if personality: 437 print("}", file=f) 438 439 for name, type, array, dir, value, personality in params: 440 if personality: 441 print("if(%s) {" % personality, file=f) 442 if array: 443 if isinstance(array, tuple): 444 lim, cnt = array 445 print(" if((%s) > (%s)) {" % (cnt, lim), file=f) 446 print(' rtapi_print_msg(RTAPI_MSG_ERR,' \ 447 '"Parameter %s: Requested size %%d exceeds max size %%d\\n",' 448 '(int)%s, (int)%s);' % (name, cnt, lim), file=f) 449 print(" return -ENOSPC;", file=f) 450 print(" }", file=f) 451 else: cnt = array 452 print(" for(j=0; j < (%s); j++) {" % cnt, file=f) 453 print(" r = hal_param_%s_newf(%s, &(inst->%s[j]), comp_id," % ( 454 type, dirmap[dir], to_c(name)), file=f) 455 print(" \"%%s%s\", prefix, j);" % to_hal("." + name), file=f) 456 print(" if(r != 0) return r;", file=f) 457 if value is not None: 458 print(" inst->%s[j] = %s;" % (to_c(name), value), file=f) 459 print(" }", file=f) 460 else: 461 print(" r = hal_param_%s_newf(%s, &(inst->%s), comp_id," % ( 462 type, dirmap[dir], to_c(name)), file=f) 463 print(" \"%%s%s\", prefix);" % to_hal("." + name), file=f) 464 if value is not None: 465 print(" inst->%s = %s;" % (to_c(name), value), file=f) 466 print(" if(r != 0) return r;", file=f) 467 if personality: 468 print("}", file=f) 469 470 for type, name, array, value in variables: 471 if value is None: continue 472 if array: 473 print(" for(j=0; j < %s; j++) {" % array, file=f) 474 print(" inst->%s[j] = %s;" % (name, value), file=f) 475 print(" }", file=f) 476 else: 477 print(" inst->%s = %s;" % (name, value), file=f) 478 479 for name, fp in functions: 480 print(" rtapi_snprintf(buf, sizeof(buf), \"%%s%s\", prefix);"\ 481 % to_hal("." + name), file=f) 482 print(" r = hal_export_funct(buf, (void(*)(void *inst, long))%s, inst, %s, 0, comp_id);" % ( 483 to_c(name), int(fp)), file=f) 484 print(" if(r != 0) return r;", file=f) 485 print(" if(__comp_last_inst) __comp_last_inst->_next = inst;", file=f) 486 print(" __comp_last_inst = inst;", file=f) 487 print(" if(!__comp_first_inst) __comp_first_inst = inst;", file=f) 488 print(" return 0;", file=f) 489 print("}", file=f) 490 491 if options.get("count_function"): 492 print("static int get_count(void);", file=f) 493 494 if options.get("rtapi_app", 1): 495 if options.get("constructable") and not options.get("singleton"): 496 print("static int export_1(char *prefix, char *argstr) {", file=f) 497 print(" int arg = simple_strtol(argstr, NULL, 0);", file=f) 498 print(" return export(prefix, arg);", file=f) 499 print("}" , file=f) 500 if not options.get("singleton") and not options.get("count_function") : 501 print("static int default_count=%s, count=0;" \ 502 % options.get("default_count", 1), file=f) 503 if options.get("userspace"): 504 print("char *names[%d] = {0,};"%(MAX_USERSPACE_NAMES), file=f) 505 else: 506 print("RTAPI_MP_INT(count, \"number of %s\");" % comp_name, file=f) 507 print("char *names = \"\"; // comma separated names", file=f) 508 print("RTAPI_MP_STRING(names, \"names of %s\");" % comp_name, file=f) 509 if has_personality: 510 init1 = str(int(options.get('default_personality', 0))) 511 init = ",".join([init1] * MAX_PERSONALITIES) 512 print("static int personality[%d] = {%s};" %(MAX_PERSONALITIES,init), file=f) 513 print("RTAPI_MP_ARRAY_INT(personality, %d, \"personality of each %s\");" %(MAX_PERSONALITIES,comp_name), file=f) 514 515 # Return personality value. 516 # If requested index excedes MAX_PERSONALITIES, use modulo indexing and give message 517 print(""" 518 static int p_value(char* cname, char *name, int idx) { 519 int ans = personality[idx%%%d]; 520 if (idx >= %d) { 521 """%(MAX_PERSONALITIES,MAX_PERSONALITIES), file=f) 522 print(""" 523 if (name==NULL) { 524 rtapi_print_msg(RTAPI_MSG_ERR,"%s: instance %d assigned personality=%d(=%#0x)\\n", 525 cname, idx, ans, ans); 526 } else { 527 rtapi_print_msg(RTAPI_MSG_ERR,"%s: name %s assigned personality=%d(=%#0x)\\n", 528 cname, name, ans, ans); 529 } 530 } 531 return ans; 532 } 533 """, file=f) 534 535 print("int rtapi_app_main(void) {", file=f) 536 print(" int r = 0;", file=f) 537 if not options.get("singleton"): 538 print(" int i;", file=f) 539 if options.get("count_function"): 540 print(" int count = get_count();", file=f) 541 542 print(" comp_id = hal_init(\"%s\");" % comp_name, file=f) 543 print(" if(comp_id < 0) return comp_id;", file=f) 544 545 if options.get("singleton"): 546 if has_personality: 547 print(" r = export(\"%s\", 0, personality[0]);" % \ 548 to_hal(removeprefix(comp_name, "hal_")), file=f) 549 else: 550 print(" r = export(\"%s\", 0);" % \ 551 to_hal(removeprefix(comp_name, "hal_")), file=f) 552 elif options.get("count_function"): 553 print(" for(i=0; i<count; i++) {", file=f) 554 print(" char buf[HAL_NAME_LEN + 1];", file=f) 555 print(" rtapi_snprintf(buf, sizeof(buf), " \ 556 "\"%s.%%d\", i);" % \ 557 to_hal(removeprefix(comp_name, "hal_")), file=f) 558 if has_personality: 559 print(" r = export(buf, i, p_value(\"%s\", buf, i) );"%comp_name, file=f) 560 else: 561 print(" r = export(buf, i);", file=f) 562 print(" }", file=f) 563 else: 564 print(" if(count && names[0]) {", file=f) 565 print(" rtapi_print_msg(RTAPI_MSG_ERR," \ 566 "\"count= and names= are mutually exclusive\\n\");", file=f) 567 print(" return -EINVAL;", file=f) 568 print(" }", file=f) 569 print(" if(!count && !names[0]) count = default_count;", file=f) 570 print(" if(count) {", file=f) 571 print(" for(i=0; i<count; i++) {", file=f) 572 print(" char buf[HAL_NAME_LEN + 1];", file=f) 573 print(" rtapi_snprintf(buf, sizeof(buf), " \ 574 "\"%s.%%d\", i);" % \ 575 to_hal(removeprefix(comp_name, "hal_")), file=f) 576 if has_personality: 577 print(" r = export(buf, i, p_value(\"%s\", buf, i) );"%comp_name, file=f) 578 else: 579 print(" r = export(buf, i);", file=f) 580 print(" if(r != 0) break;", file=f) 581 print(" }", file=f) 582 print(" } else {", file=f) 583 if options.get("userspace"): 584 print(" int max_names = sizeof(names)/sizeof(names[0]);", file=f) 585 print(" for(i=0; (i < max_names) && names[i]; i++) {", file=f) 586 print(" if (strlen(names[i]) < 1) {", file=f) 587 print(" rtapi_print_msg(RTAPI_MSG_ERR, \"names[%d] is invalid (empty string)\\n\", i);", file=f) 588 print(" r = -EINVAL;", file=f) 589 print(" break;", file=f) 590 print(" }", file=f) 591 if has_personality: 592 print(" r = export(names[i], i, p_value(\"%s\", names[i], i) );"%comp_name, file=f) 593 else: 594 print(" r = export(names[i], i);", file=f) 595 print(" if(r != 0) break;", file=f) 596 print(" }", file=f) 597 print(" }", file=f) 598 else: 599 print(" int j,idx;", file=f) 600 print(" char *ptr;", file=f) 601 print(" char buf[HAL_NAME_LEN+1];", file=f) 602 print(" ptr = names;", file=f) 603 print(" idx = 0;", file=f) 604 print(" for (i=0,j=0; i <= strlen(names); i++) {", file=f) 605 print(" buf[j] = *(ptr+i);", file=f) 606 print(" if ( (*(ptr+i) == ',') || (*(ptr+i) == 0) ) {", file=f) 607 print(" buf[j] = 0;", file=f) 608 if has_personality: 609 print(" r = export(buf, idx, p_value(\"%s\", buf, idx) );"%comp_name, file=f) 610 else: 611 print(" r = export(buf, idx);", file=f) 612 print(" if (*(ptr+i+1) == 0) {break;}", file=f) 613 print(" idx++;", file=f) 614 print(" if(r != 0) {break;}", file=f) 615 print(" j=0;", file=f) 616 print(" } else {", file=f) 617 print(" j++;", file=f) 618 print(" }", file=f) 619 print(" }", file=f) 620 print(" }", file=f) 621 622 if options.get("constructable") and not options.get("singleton"): 623 print(" hal_set_constructor(comp_id, export_1);", file=f) 624 print(" if(r) {", file=f) 625 if options.get("extra_cleanup"): 626 print(" extra_cleanup();", file=f) 627 print(" hal_exit(comp_id);", file=f) 628 print(" } else {", file=f) 629 print(" hal_ready(comp_id);", file=f) 630 print(" }", file=f) 631 print(" return r;", file=f) 632 print("}", file=f) 633 634 print("", file=f) 635 print("void rtapi_app_exit(void) {", file=f) 636 if options.get("extra_cleanup"): 637 print(" extra_cleanup();", file=f) 638 print(" hal_exit(comp_id);", file=f) 639 print("}", file=f) 640 641 if options.get("userspace"): 642 print("static void user_mainloop(void);", file=f) 643 if options.get("userinit"): 644 print("static void userinit(int argc, char **argv);", file=f) 645 646 if not options.get("singleton"): 647 print(""" 648 int __comp_parse_count(int *argc, char **argv) { 649 int i; 650 for (i = 0; i < *argc; i ++) { 651 if (strncmp(argv[i], "count=", 6) == 0) { 652 errno = 0; 653 count = strtoul(&argv[i][6], NULL, 0); 654 for (; i+1 < *argc; i ++) { 655 argv[i] = argv[i+1]; 656 } 657 argv[i] = NULL; 658 (*argc)--; 659 if (errno == 0) { 660 return 1; 661 } 662 } 663 } 664 return 0; 665 } 666 """, file=f) 667 print(""" 668 int __comp_parse_names(int *argc, char **argv) { 669 int i; 670 for (i = 0; i < *argc; i ++) { 671 if (strncmp(argv[i], "names=", 6) == 0) { 672 char *p = &argv[i][6]; 673 int j; 674 for (; i+1 < *argc; i ++) { 675 argv[i] = argv[i+1]; 676 } 677 argv[i] = NULL; 678 (*argc)--; 679 for (j = 0; j < %d; j ++) { 680 names[j] = strtok(p, ","); 681 p = NULL; 682 if (names[j] == NULL) { 683 return 1; 684 } 685 } 686 return 1; 687 } 688 } 689 return 0; 690 } 691 """%MAX_USERSPACE_NAMES, file=f) 692 print("int argc=0; char **argv=0;", file=f) 693 print("int main(int argc_, char **argv_) {" , file=f) 694 print(" argc = argc_; argv = argv_;", file=f) 695 if not options.get("singleton"): 696 print(" int found_count, found_names;", file=f) 697 print(" found_count = __comp_parse_count(&argc, argv);", file=f) 698 print(" found_names = __comp_parse_names(&argc, argv);", file=f) 699 print(" if (found_count && found_names) {", file=f) 700 print(" rtapi_print_msg(RTAPI_MSG_ERR, \"count= and names= are mutually exclusive\\n\");", file=f) 701 print(" return 1;", file=f) 702 print(" }", file=f) 703 if options.get("userinit", 0): 704 print(" userinit(argc, argv);", file=f) 705 print("", file=f) 706 print(" if(rtapi_app_main() < 0) return 1;", file=f) 707 print(" user_mainloop();", file=f) 708 print(" rtapi_app_exit();", file=f) 709 print(" return 0;", file=f) 710 print("}", file=f) 711 712 print("", file=f) 713 if not options.get("no_convenience_defines"): 714 print("#undef FUNCTION", file=f) 715 print("#define FUNCTION(name) static void name(struct __comp_state *__comp_inst, long period)", file=f) 716 print("#undef EXTRA_SETUP", file=f) 717 print("#define EXTRA_SETUP() static int extra_setup(struct __comp_state *__comp_inst, char *prefix, long extra_arg)", file=f) 718 print("#undef EXTRA_CLEANUP", file=f) 719 print("#define EXTRA_CLEANUP() static void extra_cleanup(void)", file=f) 720 print("#undef fperiod", file=f) 721 print("#define fperiod (period * 1e-9)", file=f) 722 for name, type, array, dir, value, personality in pins: 723 print("#undef %s" % to_c(name), file=f) 724 if array: 725 if dir == 'in': 726 print("#define %s(i) (0+*(__comp_inst->%s[i]))" % (to_c(name), to_c(name)), file=f) 727 else: 728 print("#define %s(i) (*(__comp_inst->%s[i]))" % (to_c(name), to_c(name)), file=f) 729 else: 730 if dir == 'in': 731 print("#define %s (0+*__comp_inst->%s)" % (to_c(name), to_c(name)), file=f) 732 else: 733 print("#define %s (*__comp_inst->%s)" % (to_c(name), to_c(name)), file=f) 734 for name, type, array, dir, value, personality in params: 735 print("#undef %s" % to_c(name), file=f) 736 if array: 737 print("#define %s(i) (__comp_inst->%s[i])" % (to_c(name), to_c(name)), file=f) 738 else: 739 print("#define %s (__comp_inst->%s)" % (to_c(name), to_c(name)), file=f) 740 741 for type, name, array, value in variables: 742 name = name.replace("*", "") 743 print("#undef %s" % name, file=f) 744 print("#define %s (__comp_inst->%s)" % (name, name), file=f) 745 746 if has_data: 747 print("#undef data", file=f) 748 print("#define data (*(%s*)(__comp_inst->_data))" % options['data'], file=f) 749 if has_personality: 750 print("#undef personality", file=f) 751 print("#define personality (__comp_inst->_personality)", file=f) 752 753 if options.get("userspace"): 754 print("#undef FOR_ALL_INSTS", file=f) 755 if options.get("singleton"): 756 print("#define __comp_inst __comp_first_inst", file=f) 757 print("#define FOR_ALL_INSTS()", file=f) 758 else: 759 print("#define FOR_ALL_INSTS() struct __comp_state *__comp_inst; for(__comp_inst = __comp_first_inst; __comp_inst; __comp_inst = __comp_inst->_next)", file=f) 760 print("", file=f) 761 print("", file=f) 762 763 def epilogue(f): 764 data = options.get('data') 765 print("", file=f) 766 if data: 767 print("static int __comp_get_data_size(void) { return sizeof(%s); }" % data, file=f) 768 else: 769 print("static int __comp_get_data_size(void) { return 0; }", file=f) 770 771 INSTALL, COMPILE, PREPROCESS, DOCUMENT, INSTALLDOC, VIEWDOC, MODINC = range(7) 772 modename = ("install", "compile", "preprocess", "document", "installdoc", "viewdoc", "print-modinc") 773 774 modinc = None 775 def find_modinc(): 776 global modinc 777 if modinc: return modinc 778 d = os.path.abspath(os.path.dirname(os.path.dirname(sys.argv[0]))) 779 for e in ['src', 'etc/linuxcnc', '/etc/linuxcnc', 'share/linuxcnc']: 780 e = os.path.join(d, e, 'Makefile.modinc') 781 if os.path.exists(e): 782 modinc = e 783 return e 784 raise SystemExit("Unable to locate Makefile.modinc") 785 786 def build_usr(tempdir, filename, mode, origfilename): 787 binname = os.path.basename(os.path.splitext(filename)[0]) 788 789 makefile = os.path.join(tempdir, "Makefile") 790 f = open(makefile, "w") 791 print("%s: %s" % (binname, filename), file=f) 792 print("\t$(CC) $(EXTRA_CFLAGS) -URTAPI -U__MODULE__ -DULAPI -Os %s -o $@ $< -Wl,-rpath,$(LIBDIR) -L$(LIBDIR) -llinuxcnchal %s" % ( 793 options.get("extra_compile_args", ""), 794 options.get("extra_link_args", "")), file=f) 795 print("include %s" % find_modinc(), file=f) 796 f.close() 797 result = os.system("cd %s && make -S %s" % (tempdir, binname)) 798 if result != 0: 799 raise SystemExit(os.WEXITSTATUS(result) or 1) 800 output = os.path.join(tempdir, binname) 801 if mode == INSTALL: 802 shutil.copy(output, os.path.join(BASE, "bin", binname)) 803 elif mode == COMPILE: 804 shutil.copy(output, os.path.join(os.path.dirname(origfilename),binname)) 805 806 def build_rt(tempdir, filename, mode, origfilename): 807 objname = os.path.basename(os.path.splitext(filename)[0] + ".o") 808 makefile = os.path.join(tempdir, "Makefile") 809 f = open(makefile, "w") 810 print("obj-m += %s" % objname, file=f) 811 print("include %s" % find_modinc(), file=f) 812 print("EXTRA_CFLAGS += -I%s" % os.path.abspath(os.path.dirname(origfilename)), file=f) 813 print("EXTRA_CFLAGS += -I%s" % os.path.abspath('.'), file=f) 814 f.close() 815 if mode == INSTALL: 816 target = "modules install" 817 else: 818 target = "modules" 819 result = os.system("cd %s && make -S %s" % (tempdir, target)) 820 if result != 0: 821 raise SystemExit(os.WEXITSTATUS(result) or 1) 822 if mode == COMPILE: 823 for extension in ".ko", ".so", ".o": 824 kobjname = os.path.splitext(filename)[0] + extension 825 if os.path.exists(kobjname): 826 shutil.copy(kobjname, os.path.basename(kobjname)) 827 break 828 else: 829 raise SystemExit("Unable to copy module from temporary directory") 830 831 def finddoc(section=None, name=None): 832 for item in docs: 833 if ((section == None or section == item[0]) and 834 (name == None or name == item[1])): return item 835 return None 836 837 def finddocs(section=None, name=None): 838 for item in docs: 839 if ((section == None or section == item[0]) and 840 (name == None or name == item[1])): 841 yield item 842 843 def to_hal_man_unnumbered(s): 844 s = "%s.%s" % (comp_name, s) 845 s = s.replace("_", "-") 846 s = s.rstrip("-") 847 s = s.rstrip(".") 848 s = re.sub("#+", lambda m: "\\fI" + "M" * len(m.group(0)) + "\\fB", s) 849 # s = s.replace("-", "\\-") 850 return s 851 852 853 def to_hal_man(s): 854 if options.get("singleton"): 855 s = "%s.%s" % (comp_name, s) 856 else: 857 s = "%s.\\fIN\\fB.%s" % (comp_name, s) 858 s = s.replace("_", "-") 859 s = s.rstrip("-") 860 s = s.rstrip(".") 861 s = re.sub("#+", lambda m: "\\fI" + "M" * len(m.group(0)) + "\\fB", s) 862 # s = s.replace("-", "\\-") 863 return s 864 865 def document(filename, outfilename): 866 if outfilename is None: 867 outfilename = os.path.splitext(filename)[0] + ".9" 868 869 a, b = parse(filename) 870 f = open(outfilename, "w") 871 872 has_personality = False 873 for name, type, array, dir, value, personality in pins: 874 if personality: has_personality = True 875 if isinstance(array, tuple): has_personality = True 876 for name, type, array, dir, value, personality in params: 877 if personality: has_personality = True 878 if isinstance(array, tuple): has_personality = True 879 880 print(".TH %s \"9\" \"%s\" \"LinuxCNC Documentation\" \"HAL Component\"" % ( 881 comp_name.upper(), time.strftime("%F")), file=f) 882 print(".de TQ\n.br\n.ns\n.TP \\\\$1\n..\n", file=f) 883 884 print(".SH NAME\n", file=f) 885 doc = finddoc('component') 886 if doc and doc[2]: 887 if '\n' in doc[2]: 888 firstline, rest = doc[2].split('\n', 1) 889 else: 890 firstline = doc[2] 891 rest = '' 892 print("%s \\- %s" % (doc[1], firstline), file=f) 893 else: 894 rest = '' 895 print("%s" % doc[1], file=f) 896 897 898 print(".SH SYNOPSIS", file=f) 899 if options.get("userspace"): 900 print(".B %s" % comp_name, file=f) 901 else: 902 if rest: 903 print(rest, file=f) 904 else: 905 print(".HP", file=f) 906 if options.get("singleton") or options.get("count_function"): 907 if has_personality: 908 print(".B loadrt %s personality=\\fIP\\fB" % comp_name, end='', file=f) 909 else: 910 print(".B loadrt %s" % comp_name, end='', file=f) 911 else: 912 if has_personality: 913 print(".B loadrt %s [count=\\fIN\\fB|names=\\fIname1\\fB[,\\fIname2...\\fB]] [personality=\\fIP,P,...\\fB]" % comp_name, end='', file=f) 914 else: 915 print(".B loadrt %s [count=\\fIN\\fB|names=\\fIname1\\fB[,\\fIname2...\\fB]]" % comp_name, end='', file=f) 916 for type, name, default, doc in modparams: 917 print(" [%s=\\fIN\\fB]" % name, end='', file=f) 918 print("", file=f) 919 920 hasparamdoc = False 921 for type, name, default, doc in modparams: 922 if doc: hasparamdoc = True 923 924 if hasparamdoc: 925 print(".RS 4", file=f) 926 for type, name, default, doc in modparams: 927 print(".TP", file=f) 928 print("\\fB%s\\fR" % name, end='', file=f) 929 if default: 930 print(" [default: %s]" % default, file=f) 931 else: 932 print("", file=f) 933 print(doc, file=f) 934 print(".RE", file=f) 935 936 if options.get("constructable") and not options.get("singleton"): 937 print(".PP\n.B newinst %s \\fIname\\fB" % comp_name, file=f) 938 939 doc = finddoc('descr') 940 if doc and doc[1]: 941 print(".SH DESCRIPTION\n", file=f) 942 print("%s" % doc[1], file=f) 943 944 if functions: 945 print(".SH FUNCTIONS", file=f) 946 for _, name, fp, doc in finddocs('funct'): 947 print(".TP", file=f) 948 print("\\fB%s\\fR" % to_hal_man(name), end='', file=f) 949 if fp: 950 print(" (requires a floating-point thread)", file=f) 951 else: 952 print("", file=f) 953 print(doc, file=f) 954 955 lead = ".TP" 956 print(".SH PINS", file=f) 957 for _, name, type, array, dir, doc, value, personality in finddocs('pin'): 958 print(lead, file=f) 959 print(".B %s\\fR" % to_hal_man(name), end=' ', file=f) 960 print(type, dir, end=' ', file=f) 961 if array: 962 sz = name.count("#") 963 if isinstance(array, tuple): 964 print(" (%s=%0*d..%s)" % ("M" * sz, sz, 0, array[1]), end=' ', file=f) 965 else: 966 print(" (%s=%0*d..%0*d)" % ("M" * sz, sz, 0, sz, array-1), end=' ', file=f) 967 if personality: 968 print(" [if %s]" % personality, end=' ', file=f) 969 if value: 970 print("\\fR(default: \\fI%s\\fR)" % value, file=f) 971 else: 972 print("\\fR", file=f) 973 if doc: 974 print(doc, file=f) 975 lead = ".TP" 976 else: 977 lead = ".TQ" 978 979 lead = ".TP" 980 if params: 981 print(".SH PARAMETERS", file=f) 982 for _, name, type, array, dir, doc, value, personality in finddocs('param'): 983 print(lead, file=f) 984 print(".B %s\\fR" % to_hal_man(name), end=' ', file=f) 985 print(type, dir, end=' ', file=f) 986 if array: 987 sz = name.count("#") 988 if isinstance(array, tuple): 989 print(" (%s=%0*d..%s)" % ("M" * sz, sz, 0, array[1]), end=' ', file=f) 990 else: 991 print(" (%s=%0*d..%0*d)" % ("M" * sz, sz, 0, sz, array-1), end=' ', file=f) 992 if personality: 993 print(" [if %s]" % personality, end=' ', file=f) 994 if value: 995 print("\\fR(default: \\fI%s\\fR)" % value, file=f) 996 else: 997 print("\\fR", file=f) 998 if doc: 999 print(doc, file=f) 1000 lead = ".TP" 1001 else: 1002 lead = ".TQ" 1003 1004 doc = finddoc('see_also') 1005 if doc and doc[1]: 1006 print(".SH SEE ALSO\n", file=f) 1007 print("%s" % doc[1], file=f) 1008 1009 doc = finddoc('notes') 1010 if doc and doc[1]: 1011 print(".SH NOTES\n", file=f) 1012 print("%s" % doc[1], file=f) 1013 1014 doc = finddoc('author') 1015 if doc and doc[1]: 1016 print(".SH AUTHOR\n", file=f) 1017 print("%s" % doc[1], file=f) 1018 1019 doc = finddoc('license') 1020 if doc and doc[1]: 1021 print(".SH LICENSE\n", file=f) 1022 print("%s" % doc[1], file=f) 1023 1024 def process(filename, mode, outfilename): 1025 tempdir = tempfile.mkdtemp() 1026 try: 1027 if outfilename is None: 1028 if mode == PREPROCESS: 1029 outfilename = os.path.splitext(filename)[0] + ".c" 1030 else: 1031 outfilename = os.path.join(tempdir, 1032 os.path.splitext(os.path.basename(filename))[0] + ".c") 1033 1034 a, b = parse(filename) 1035 base_name = os.path.splitext(os.path.basename(outfilename))[0] 1036 if comp_name != base_name: 1037 raise SystemExit("Component name (%s) does not match filename (%s)" % (comp_name, base_name)) 1038 1039 f = open(outfilename, "w") 1040 1041 if options.get("userinit") and not options.get("userspace"): 1042 print("Warning: comp '%s' sets 'userinit' without 'userspace', ignoring" % filename, file=sys.stderr) 1043 1044 if options.get("userspace"): 1045 if functions: 1046 raise SystemExit("Userspace components may not have functions") 1047 if not pins: 1048 raise SystemExit("Component must have at least one pin") 1049 prologue(f) 1050 lineno = a.count("\n") + 3 1051 1052 if options.get("userspace"): 1053 if functions: 1054 raise SystemExit("May not specify functions with a userspace component.") 1055 f.write("#line %d \"%s\"\n" % (lineno, filename)) 1056 f.write(b) 1057 else: 1058 if not functions or "FUNCTION" in b: 1059 f.write("#line %d \"%s\"\n" % (lineno, filename)) 1060 f.write(b) 1061 elif len(functions) == 1: 1062 f.write("FUNCTION(%s) {\n" % functions[0][0]) 1063 f.write("#line %d \"%s\"\n" % (lineno, filename)) 1064 f.write(b) 1065 f.write("}\n") 1066 else: 1067 raise SystemExit("Must use FUNCTION() when more than one function is defined") 1068 epilogue(f) 1069 f.close() 1070 1071 if mode != PREPROCESS: 1072 if options.get("userspace"): 1073 build_usr(tempdir, outfilename, mode, filename) 1074 else: 1075 build_rt(tempdir, outfilename, mode, filename) 1076 1077 finally: 1078 shutil.rmtree(tempdir) 1079 1080 def usage(exitval=0): 1081 print("""%(name)s: Build, compile, and install LinuxCNC HAL components 1082 1083 Usage: 1084 %(name)s [--compile|--preprocess|--document|--view-doc] compfile... 1085 [sudo] %(name)s [--install|--install-doc] compfile... 1086 %(name)s --compile --userspace cfile... 1087 [sudo] %(name)s --install --userspace cfile... 1088 [sudo] %(name)s --install --userspace pyfile... 1089 %(name)s --print-modinc 1090 1091 Option to set maximum 'personalities' items: 1092 --personalities=integer_value (default is %(dflt)d) 1093 """ % {'name': os.path.basename(sys.argv[0]),'dflt':MAX_PERSONALITIES}) 1094 raise SystemExit(exitval) 1095 1096 def main(): 1097 global require_license 1098 global MAX_USERSPACE_NAMES 1099 global MAX_PERSONALITIES 1100 require_license = True 1101 global require_unix_line_endings 1102 require_unix_line_endings = False 1103 mode = PREPROCESS 1104 outfile = None 1105 userspace = False 1106 try: 1107 opts, args = getopt.getopt(sys.argv[1:], "Uluijcpdo:h?P:", 1108 ['unix', 'install', 'compile', 'preprocess', 'outfile=', 1109 'document', 'help', 'userspace', 'install-doc', 1110 'view-doc', 'require-license', 'print-modinc', 1111 'personalities=']) 1112 except getopt.GetoptError: 1113 usage(1) 1114 1115 for k, v in opts: 1116 if k in ("-U", "--unix"): 1117 require_unix_line_endings = True 1118 if k in ("-u", "--userspace"): 1119 userspace = True 1120 if k in ("-i", "--install"): 1121 mode = INSTALL 1122 if k in ("-c", "--compile"): 1123 mode = COMPILE 1124 if k in ("-p", "--preprocess"): 1125 mode = PREPROCESS 1126 if k in ("-d", "--document"): 1127 mode = DOCUMENT 1128 if k in ("-j", "--install-doc"): 1129 mode = INSTALLDOC 1130 if k in ("-j", "--view-doc"): 1131 mode = VIEWDOC 1132 if k in ("--print-modinc",): 1133 mode = MODINC 1134 if k in ("-l", "--require-license"): 1135 require_license = True 1136 if k in ("-o", "--outfile"): 1137 if len(args) != 1: 1138 raise SystemExit("Cannot specify -o with multiple input files") 1139 outfile = v 1140 if k in ("-P", "--personalities"): 1141 try: 1142 MAX_PERSONALITIES = int(v) 1143 print("MAX_PERSONALITIES=%d"%(MAX_PERSONALITIES)) 1144 except Exception as detail: 1145 raise SystemExit("Bad value for -P (--personalities)=",v,"\n",detail) 1146 if k in ("-?", "-h", "--help"): 1147 usage(0) 1148 1149 if outfile and mode != PREPROCESS and mode != DOCUMENT: 1150 raise SystemExit("Can only specify -o when preprocessing or documenting") 1151 1152 if mode == MODINC: 1153 if args: 1154 raise SystemExit( 1155 "Can not specify input files when using --print-modinc") 1156 print(find_modinc()) 1157 return 0 1158 1159 for f in args: 1160 try: 1161 basename = os.path.basename(os.path.splitext(f)[0]) 1162 if f.endswith(".comp") and mode == DOCUMENT: 1163 document(f, outfile) 1164 elif f.endswith(".comp") and mode == VIEWDOC: 1165 tempdir = tempfile.mkdtemp() 1166 try: 1167 outfile = os.path.join(tempdir, basename + ".9") 1168 document(f, outfile) 1169 os.spawnvp(os.P_WAIT, "man", ["man", outfile]) 1170 finally: 1171 shutil.rmtree(tempdir) 1172 elif f.endswith(".comp") and mode == INSTALLDOC: 1173 manpath = os.path.join(BASE, "share/man/man9") 1174 if not os.path.isdir(manpath): 1175 manpath = os.path.join(BASE, "docs/man/man9") 1176 outfile = os.path.join(manpath, basename + ".9") 1177 print("INSTALLDOC", outfile) 1178 document(f, outfile) 1179 elif f.endswith(".comp"): 1180 process(f, mode, outfile) 1181 elif f.endswith(".py") and mode == INSTALL: 1182 lines = open(f).readlines() 1183 if lines[0].startswith("#!"): del lines[0] 1184 lines[0] = "#!%s\n" % sys.executable 1185 outfile = os.path.join(BASE, "bin", basename) 1186 try: os.unlink(outfile) 1187 except os.error: pass 1188 open(outfile, "w").writelines(lines) 1189 os.chmod(outfile, 0o555) 1190 elif f.endswith(".c") and mode != PREPROCESS: 1191 initialize() 1192 tempdir = tempfile.mkdtemp() 1193 try: 1194 shutil.copy(f, tempdir) 1195 if userspace: 1196 build_usr(tempdir, os.path.join(tempdir, os.path.basename(f)), mode, f) 1197 else: 1198 build_rt(tempdir, os.path.join(tempdir, os.path.basename(f)), mode, f) 1199 finally: 1200 shutil.rmtree(tempdir) 1201 else: 1202 raise SystemExit("Unrecognized file type for mode %s: %r" % (modename[mode], f)) 1203 except Exception as e: 1204 try: 1205 if outfile is not None: os.unlink(outfile) 1206 except: # os.error: 1207 pass 1208 raise 1209 if __name__ == '__main__': 1210 main() 1211 1212 # vim:sw=4:sts=4:et