1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME 80** 81** SYSDEP.C 82** 83** FACILITY: 84** 85** Interface Definition Language (IDL) Compiler 86** 87** ABSTRACT: 88** 89** Operating system dependencies. 90** 91** VERSION: DCE 1.0 92** 93*/ 94 95#include <nidl.h> 96 97#include <sys/types.h> 98#include <sys/stat.h> 99 100#ifndef MAX_INCLUSION_DEPTH 101# define MAX_INCLUSION_DEPTH 10 102#endif 103 104#ifndef HASPOPEN 105static int temp_count = 0; 106static char *temp_names[MAX_INCLUSION_DEPTH]; 107 108char *sysdep_save_temp 109( 110 char *old_name 111) 112{ 113 char new_name[64]; 114 char *new_name_ptr; 115 sprintf(new_name,"IDL%02d.TMP", temp_count); 116 new_name_ptr = temp_names[temp_count] = NEW_VEC (char, strlen(new_name) + 1); 117 strlcpy(temp_names[temp_count++], new_name, strlen(new_name) + 1); 118 unlink(new_name); 119 if(rename(old_name, new_name)) 120 { 121 error(NIDL_RENAMEFAILED,old_name,new_name); 122 } 123 return(new_name_ptr); 124} 125 126void sysdep_cleanup_temp 127() 128{ 129 int i; 130 char *name; 131 132 for(i = 0; i < temp_count; i++) 133 { 134 name = temp_names[i]; 135 free(temp_names[i]); 136 temp_names[i] = (char *) 0; 137 if(name) 138 { 139 unlink(temp_names[i]); 140 } 141 } 142 temp_count = 0; 143} 144 145#endif 146 147#if defined(IDL_USE_OUTPUT_LINE) 148#undef fprintf 149 150/* 151** isidchar - tests whether a character is a valid identifier character: 152** alphanumeric or an underscore. 153*/ 154#define isidchar(c) \ 155 ( (c) == '_' \ 156 || ((c) >= 'a' && (c) <= 'z') \ 157 || ((c) >= 'A' && (c) <= 'Z') \ 158 || ((c) >= '0' && (c) <= '9') ) 159 160/* 161** Choose an arbitrary large limit for the longest line length. 162** Sorry, but we have to have one. Note that (LINE_BUFF_SIZE - MAX_C_LINE_LEN) 163** is the largest size output string that is guaranteed to fit in the buffer. 164*/ 165#define LINE_BUFF_SIZE 2048 166#ifdef DUMPERS 167#define MAX_C_LINE_LEN 80 168#else 169#define MAX_C_LINE_LEN 132 170#endif 171#define MAX_FORMAT_LEN 255 172#define INDENT_SP_PER_LVL 2 173#include <stdarg.h> 174#include <stdio.h> 175 176static char out_buffer[LINE_BUFF_SIZE]; /* Buffer for outputs */ 177static char new_format[MAX_FORMAT_LEN]; /* Buffer for modified format string */ 178static int buff_len = 0; /* Length of current data in buffer */ 179static int indent_sp = 0; /* Number of spaces to indent */ 180static FILE * previous_fid = NULL; /* File id from previous call */ 181 182/* 183** f l u s h _ o u t p u t _ l i n e 184** 185** Routine that must be called after all output_line calls to a file are 186** complete, to write any leftover data to the given file. 187** It can be called at other times if desired. 188** 189** Implicit inputs: out_buffer, buff_len, previous_fid 190*/ 191 192void flush_output_line 193( 194 FILE * fid /* [in] File handle */ 195) 196{ 197 /* 198 ** If fid does not match fid from last call to output_line, this is a noop 199 ** since output_line always calls this routine on a fid switch so that 200 ** data isn't lost for a previous fid. 201 */ 202 if (fid != previous_fid) 203 return; 204 205 /* 206 ** Data always starts at out_buffer[0]; buff_len is length of data. 207 */ 208 if (fid != NULL && buff_len > 0) 209 { 210 out_buffer[buff_len] = '\0'; 211 fprintf (fid, "%s", out_buffer); 212 buff_len = 0; 213 } 214} 215 216/* 217** o u t p u t _ l i n e 218** 219** Replacement routine for fprintf() for use by the backend on platforms 220** whose C compiler has a limit of N characters per source line. A call to 221** fprintf, or a series of calls to fprintf without a newline character, can 222** cause source lines greater than N characters. This routine assures that 223** no source lines over N characters will be output by breaking long lines 224** up into more than one line when necessary. 225** 226** Implicit inputs: out_buffer, buff_len, previous_fid 227*/ 228 229int output_line 230( 231 FILE * fid, /* [in] File handle */ 232 char *format, /* [in] Format string */ 233 ... /* [in] 0-N format arguments */ 234) 235{ 236 va_list args; 237 char *buff, *obuff, *cp, *pcp; 238 char temp; 239 int i, j, len, new_len; 240 241 va_start (args, format); 242 243 /* 244 ** If not the same fid as the last call, flush the output buffer for the 245 ** previous fid if it has any data. This makes us lose track of that fid, 246 ** and a illegally long line becomes possible. 247 */ 248 if (fid != previous_fid) 249 { 250 if (buff_len > 0) 251 flush_output_line(previous_fid); 252 previous_fid = fid; 253 } 254 255 /* 256 ** When data is buffered across calls, it always begins at out_buffer[0]. 257 ** buff points to the next chunk of the data to be output. 258 ** buff_len counts the remaining number of bytes to be output. 259 */ 260 buff = obuff = out_buffer; 261 262 /* 263 ** Munge the format string for indentation. 264 */ 265 new_len = 0; 266 267 for (pcp = cp = format ; *cp ; cp++) 268 { 269 switch (*cp) 270 { 271 case '\n': 272 /* 273 ** Copy format string through newline [and insert indentation]. 274 */ 275 len = cp - pcp + 1; 276 strncpy(&new_format[new_len], pcp, len); 277 pcp = cp + 1; 278 new_len += len; 279 /* 280 ** Lookahead: special case logic for certain next characters. 281 */ 282 if (cp[1] == '\0' || cp[1] == '#') 283 break; /* Don't insert indentation */ 284 j = ((cp[1] == '}') ? indent_sp - INDENT_SP_PER_LVL : indent_sp); 285 for (i = 0 ; i < j ; i++) 286 new_format[new_len++] = ' '; 287 break; 288 289 case '{': 290 indent_sp += INDENT_SP_PER_LVL; 291 break; 292 293 case '}': 294 /* 295 ** Reduce indent level in buf if '}' first char of format string. 296 */ 297 if (cp == format && buff_len == indent_sp) 298 buff_len -= INDENT_SP_PER_LVL; 299 indent_sp -= INDENT_SP_PER_LVL; 300 break; 301 302 case '#': 303 /* 304 ** Remove indentation in buf if '#' first char of format string. 305 */ 306 if (cp == format && buff_len == indent_sp) 307 buff_len = 0; 308 break; 309 310 default: 311 break; 312 } 313 } 314 315 strlcpy(&new_format[new_len], pcp, sizeof (new_format) - new_len); /* Copy rest of format string */ 316 buff_len += vsprintf (&buff[buff_len], new_format, args); 317 318 j = 0; /* Counts quote characters in logic below */ 319 while (buff_len > MAX_C_LINE_LEN) 320 { 321 /* 322 ** The buffer could contain embedded Newlines, in which case it is not 323 ** necessarily too long to output in a single fprintf. To simplify the 324 ** logic, though, scan for Newlines within the line limit and if found, 325 ** do a separate fprintf and update pointers. 326 */ 327 cp = strchr(buff, '\n'); 328 if (cp != 0 && (cp - buff) <= MAX_C_LINE_LEN) 329 { 330 temp = *++cp; 331 *cp = '\0'; 332 fprintf (fid, "%s", buff); 333 } 334 else 335 { 336#ifdef CONTINUATION_METHOD 337 /* 338 ** VAX C only allows the '\' continuation character in #defines, 339 ** tokens, and character strings. Since we have no way of knowing 340 ** whether we're in a #define or a character string, we want to make 341 ** sure we break the line in the middle of a token. The code below 342 ** assumes that we are guaranteed to find two consecutive token 343 ** characters when we scan back in the buffer, and does the line 344 ** break in between those two characters. 345 */ 346 for (cp = &buff[MAX_C_LINE_LEN-1] ;; cp--) 347 if (isidchar(*cp) && isidchar(cp[-1])) 348 break; 349#else 350 /* 351 ** Scan backwards for a "break" char that is not in a literal string 352 ** and output up through that break char followed by a newline. 353 */ 354 char *dpos = NULL, *odpos, *endpos; 355 356 /* 357 * Find the rightmost delimiter and count quotes. 358 */ 359 endpos = &buff[MAX_C_LINE_LEN-1]; 360 temp = *endpos; /* Save end char */ 361 *endpos = '\0'; /* Temp make eos */ 362 363 cp = buff; 364 while ((cp = strpbrk(cp, " .,-\"()")) != NULL) 365 { 366 if (*cp == '"') 367 { 368 j++; 369 odpos = dpos; /* Save delim pos before this quote */ 370 dpos = cp; /* Save as possible delimiter */ 371 } 372 else if (*cp == '-' && *++cp != '>') 373 continue; 374 else 375 dpos = cp; 376 cp++; 377 } 378 379 *endpos = temp; /* Restore end char */ 380 381 /* 382 * Got the rightmost delimiter but if quote count is odd then it 383 * is within a quoted string so back off to the previous delimiter 384 * before the quote. 385 */ 386 if (j%2 == 1 && odpos != NULL) 387 dpos = odpos; 388 389 if (dpos == NULL) 390 /* Didn't find a break char; punt and output entire line. */ 391 cp = &buff[buff_len]; 392 else 393 cp = dpos + 1; 394#endif 395 396 /* 397 ** cp now points at the character after where we want to split. 398 ** Put a temporary break in the buffer so we can print this section. 399 */ 400 temp = *cp; 401 *cp = '\0'; 402#ifdef CONTINUATION_METHOD 403 fprintf (fid, "%s\\\n", buff); 404#else 405 fprintf (fid, "%s\n", buff); 406#endif 407 } 408 409 /* 410 ** Restore the saved character, update length and pointers, try again. 411 */ 412 *cp = temp; 413 buff_len = buff_len - ((uintptr_t)cp - (uintptr_t)buff); 414 buff = cp; 415 } 416 417 /* 418 ** Output the final part of the line. buff points somewhere within 419 ** out_buffer, at the start of the final part of the line. 420 */ 421 if (buff[buff_len-1] == '\n') 422 { 423 /* 424 ** The last character in the buffer is a newline. 425 ** Output the buffer now and reinitialize buffer and index. 426 */ 427 fprintf (fid, "%s", buff); 428 for (buff_len = 0 ; buff_len < indent_sp ; obuff[buff_len++] = ' ') 429 ; 430 } 431 else 432 { 433 /* 434 ** The last character in the buffer is not a newline. 435 ** If the current data in the buffer starts at other than 436 ** out_buffer[0], shift it in the buffer so that it does. 437 */ 438 if (buff != obuff) 439 { 440 i = buff_len; 441 while (i-- > 0) 442 *obuff++ = *buff++; 443 } 444 } 445} 446 447#endif 448