10Sduke/* 29330Slana * Copyright 1991 Massachusetts Institute of Technology 30Sduke * 40Sduke * Permission to use, copy, modify, distribute, and sell this software and its 50Sduke * documentation for any purpose is hereby granted without fee, provided that 60Sduke * the above copyright notice appear in all copies and that both that 70Sduke * copyright notice and this permission notice appear in supporting 80Sduke * documentation, and that the name of M.I.T. not be used in advertising or 90Sduke * publicity pertaining to distribution of the software without specific, 100Sduke * written prior permission. M.I.T. makes no representations about the 110Sduke * suitability of this software for any purpose. It is provided "as is" 120Sduke * without express or implied warranty. 130Sduke * 140Sduke * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 150Sduke * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. 160Sduke * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 170Sduke * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 180Sduke * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 192362Sohair * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 202362Sohair * 212362Sohair */ 220Sduke/* 230Sduke * xditview -- 240Sduke * 250Sduke * Display ditroff output in an X window 260Sduke */ 270Sduke 280Sduke#ifndef SABER 290Sduke#ifndef lint 300Sdukestatic char rcsid[] = "$XConsortium: xditview.c,v 1.17 89/12/10 17:05:08 rws Exp $"; 3114600Sdl#endif /* lint */ 3213172Sdl#endif /* SABER */ 3313172Sdl 3413172Sdl#ifdef HAVE_CONFIG_H 3513172Sdl#include <config.h> 3613172Sdl#endif 3713172Sdl 3813172Sdl#include <X11/Xatom.h> 390Sduke#include <X11/Xlib.h> 400Sduke#include <X11/Xos.h> 410Sduke#include <X11/Intrinsic.h> 420Sduke#include <X11/StringDefs.h> 430Sduke#include <X11/Shell.h> 440Sduke#include <X11/Xaw/Paned.h> 457369Salanb#include <X11/Xaw/Viewport.h> 460Sduke#include <X11/Xaw/Box.h> 470Sduke#include <X11/Xaw/Command.h> 480Sduke#include <X11/Xaw/Dialog.h> 490Sduke#include <X11/Xaw/Label.h> 500Sduke#include <X11/Xaw/SimpleMenu.h> 510Sduke#include <X11/Xaw/SmeBSB.h> 520Sduke 530Sduke#include <stdlib.h> 540Sduke#include <signal.h> 550Sduke#include <stdio.h> 560Sduke 570Sduke#include "Dvi.h" 580Sduke 5914600Sdl#include "xdit.bm" 6014600Sdl#include "xdit_mask.bm" 6114600Sdl 620Sduke#ifdef NEED_DECLARATION_POPEN 6314600SdlFILE *popen(const char *, const char *); 6414600Sdl#endif /* NEED_DECLARATION_POPEN */ 6514600Sdl 6614600Sdl#ifdef NEED_DECLARATION_PCLOSE 6714600Sdlint pclose (FILE *); 6814600Sdl#endif /* NEED_DECLARATION_PCLOSE */ 6914600Sdl 7014600Sdltypedef void (*MakePromptFunc)(const char *); 710Sduke 7214600Sdlstatic String fallback_resources[] = { 7314600Sdl#include "GXditview-ad.h" 740Sduke NULL 7514600Sdl}; 7614600Sdl 770Sdukestatic struct app_resources { 7814600Sdl char *print_command; 7914600Sdl char *filename; 8014600Sdl} app_resources; 8114600Sdl 8214600Sdl#define offset(field) XtOffset(struct app_resources *, field) 8314600Sdl 8414600Sdl/* Application resources. */ 850Sduke 8614600Sdlstatic XtResource resources[] = { 8714600Sdl {(String)"printCommand", (String)"PrintCommand", (String)XtRString, 880Sduke sizeof(char*), offset(print_command), (String)XtRString, NULL}, 890Sduke {(String)"filename", (String)"Filename", (String)XtRString, 900Sduke sizeof(char*), offset(filename), (String)XtRString, NULL}, 910Sduke}; 920Sduke 930Sduke#undef offset 940Sduke 950Sduke/* Command line options table. Only resources are entered here...there is a 960Sduke pass over the remaining options after XtParseCommand is let loose. */ 970Sduke 980Sdukestatic XrmOptionDescRec options[] = { 990Sduke{(char *)"-page", (char *)"*dvi.pageNumber", 1000Sduke XrmoptionSepArg, NULL}, 1010Sduke{(char *)"-backingStore", (char *)"*dvi.backingStore", 1020Sduke XrmoptionSepArg, NULL}, 1030Sduke{(char *)"-resolution", (char *)"*dvi.resolution", 1040Sduke XrmoptionSepArg, NULL}, 1050Sduke{(char *)"-printCommand", (char *)".printCommand", 1060Sduke XrmoptionSepArg, NULL}, 10714600Sdl{(char *)"-filename", (char *)".filename", 10814600Sdl XrmoptionSepArg, NULL}, 10914600Sdl{(char *)"-noPolyText", (char *)"*dvi.noPolyText", 11014600Sdl XrmoptionNoArg, (XPointer)"TRUE"}, 11114600Sdl}; 11214600Sdl 1130Sdukestatic char current_print_command[1024]; 1140Sduke 1150Sdukestatic char current_file_name[1024]; 1160Sdukestatic FILE *current_file; 1170Sduke 1180Sduke/* 1190Sduke * Report the syntax for calling xditview. 1200Sduke */ 1210Sduke 1220Sdukestatic void 1230SdukeSyntax(const char *call) 1240Sduke{ 1250Sduke (void) printf ("Usage: %s [-fg <color>] [-bg <color>]\n", call); 1260Sduke (void) printf (" [-bd <color>] [-bw <pixels>] [-help]\n"); 1270Sduke (void) printf (" [-display displayname] [-geometry geom]\n"); 1280Sduke (void) printf (" [-page <page-number>] [-backing <backing-store>]\n"); 1290Sduke (void) printf (" [-resolution <res>] [-print <command>]\n"); 1300Sduke (void) printf (" [-filename <file>] [filename]\n\n"); 1310Sduke exit(1); 1320Sduke} 1330Sduke 1340Sdukestatic void NewFile (const char *); 1350Sdukestatic void SetPageNumber (int); 1360Sdukestatic Widget toplevel, paned, viewport, dvi; 1370Sdukestatic Widget page; 1380Sdukestatic Widget simpleMenu; 1390Sduke 1400Sdukestatic void NextPage(Widget, XtPointer, XtPointer); 1410Sdukestatic void PreviousPage(Widget, XtPointer, XtPointer); 1420Sdukestatic void SelectPage(Widget, XtPointer, XtPointer); 1430Sdukestatic void OpenFile(Widget, XtPointer, XtPointer); 1440Sdukestatic void Quit(Widget, XtPointer, XtPointer); 1450Sdukestatic void Print(Widget, XtPointer, XtPointer); 1460Sduke 1470Sdukestatic struct menuEntry { 1480Sduke const char *name; 1490Sduke XtCallbackProc function; 1500Sduke} menuEntries[] = { 15116161Sdl {"nextPage", NextPage}, 15216161Sdl {"previousPage", PreviousPage}, 1537369Salanb {"selectPage", SelectPage}, 1547369Salanb {"print", Print}, 1550Sduke {"openFile", OpenFile}, 156 {"quit", Quit}, 157}; 158 159static void NextPageAction(Widget, XEvent *, String *, Cardinal *); 160static void PreviousPageAction(Widget, XEvent *, String *, Cardinal *); 161static void SelectPageAction(Widget, XEvent *, String *, Cardinal *); 162static void OpenFileAction(Widget, XEvent *, String *, Cardinal *); 163static void QuitAction(Widget, XEvent *, String *, Cardinal *); 164static void AcceptAction(Widget, XEvent *, String *, Cardinal *); 165static void CancelAction(Widget, XEvent *, String *, Cardinal *); 166static void PrintAction(Widget, XEvent *, String *, Cardinal *); 167static void RerasterizeAction(Widget, XEvent *, String *, Cardinal *); 168 169static void MakePrompt(Widget, const char *, MakePromptFunc, const char *); 170 171XtActionsRec xditview_actions[] = { 172 {(String)"NextPage", NextPageAction}, 173 {(String)"PreviousPage", PreviousPageAction}, 174 {(String)"SelectPage", SelectPageAction}, 175 {(String)"Print", PrintAction}, 176 {(String)"OpenFile", OpenFileAction}, 177 {(String)"Rerasterize", RerasterizeAction}, 178 {(String)"Quit", QuitAction}, 179 {(String)"Accept", AcceptAction}, 180 {(String)"Cancel", CancelAction}, 181}; 182 183#define MenuNextPage 0 184#define MenuPreviousPage 1 185#define MenuSelectPage 2 186#define MenuPrint 3 187#define MenuOpenFile 4 188#define MenuQuit 5 189 190static char pageLabel[256] = "Page <none>"; 191 192int main(int argc, char **argv) 193{ 194 char *file_name = 0; 195 Cardinal i; 196 static Arg labelArgs[] = { 197 {XtNlabel, (XtArgVal) pageLabel}, 198 }; 199 XtAppContext xtcontext; 200 Arg topLevelArgs[2]; 201 Widget entry; 202 Arg pageNumberArgs[1]; 203 int page_number; 204 205 toplevel = XtAppInitialize(&xtcontext, "GXditview", 206 options, XtNumber (options), 207 &argc, argv, fallback_resources, NULL, 0); 208 if (argc > 2 209 || (argc == 2 && (!strcmp(argv[1], "-help") 210 || !strcmp(argv[1], "--help")))) 211 Syntax(argv[0]); 212 213 XtGetApplicationResources(toplevel, (XtPointer)&app_resources, 214 resources, XtNumber(resources), 215 NULL, (Cardinal) 0); 216 if (app_resources.print_command) 217 strcpy(current_print_command, app_resources.print_command); 218 219 XtAppAddActions(xtcontext, xditview_actions, XtNumber (xditview_actions)); 220 221 XtSetArg (topLevelArgs[0], XtNiconPixmap, 222 XCreateBitmapFromData (XtDisplay (toplevel), 223 XtScreen(toplevel)->root, 224 (char *)xdit_bits, 225 xdit_width, xdit_height)); 226 227 XtSetArg (topLevelArgs[1], XtNiconMask, 228 XCreateBitmapFromData (XtDisplay (toplevel), 229 XtScreen(toplevel)->root, 230 (char *)xdit_mask_bits, 231 xdit_mask_width, xdit_mask_height)); 232 XtSetValues (toplevel, topLevelArgs, 2); 233 if (argc > 1) 234 file_name = argv[1]; 235 236 /* 237 * create the menu and insert the entries 238 */ 239 simpleMenu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, toplevel, 240 NULL, 0); 241 for (i = 0; i < XtNumber (menuEntries); i++) { 242 entry = XtCreateManagedWidget(menuEntries[i].name, 243 smeBSBObjectClass, simpleMenu, 244 NULL, (Cardinal) 0); 245 XtAddCallback(entry, XtNcallback, menuEntries[i].function, NULL); 246 } 247 248 paned = XtCreateManagedWidget("paned", panedWidgetClass, toplevel, 249 NULL, (Cardinal) 0); 250 viewport = XtCreateManagedWidget("viewport", viewportWidgetClass, paned, 251 NULL, (Cardinal) 0); 252 dvi = XtCreateManagedWidget ("dvi", dviWidgetClass, viewport, NULL, 0); 253 page = XtCreateManagedWidget ("label", labelWidgetClass, paned, 254 labelArgs, XtNumber (labelArgs)); 255 XtSetArg (pageNumberArgs[0], XtNpageNumber, &page_number); 256 XtGetValues (dvi, pageNumberArgs, 1); 257 if (file_name) 258 NewFile (file_name); 259 /* NewFile modifies current_file_name, so do this here. */ 260 if (app_resources.filename) 261 strcpy(current_file_name, app_resources.filename); 262 XtRealizeWidget (toplevel); 263 if (file_name) 264 SetPageNumber (page_number); 265 XtAppMainLoop(xtcontext); 266 return 0; 267} 268 269static void 270SetPageNumber (int number) 271{ 272 Arg arg[2]; 273 int actual_number, last_page; 274 275 XtSetArg (arg[0], XtNpageNumber, number); 276 XtSetValues (dvi, arg, 1); 277 XtSetArg (arg[0], XtNpageNumber, &actual_number); 278 XtSetArg (arg[1], XtNlastPageNumber, &last_page); 279 XtGetValues (dvi, arg, 2); 280 if (actual_number == 0) 281 sprintf (pageLabel, "Page <none>"); 282 else if (last_page > 0) 283 sprintf (pageLabel, "Page %d of %d", actual_number, last_page); 284 else 285 sprintf (pageLabel, "Page %d", actual_number); 286 XtSetArg (arg[0], XtNlabel, pageLabel); 287 XtSetValues (page, arg, 1); 288} 289 290static void 291SelectPageNumber (const char *number_string) 292{ 293 SetPageNumber (atoi(number_string)); 294} 295 296static int hadFile = 0; 297 298static void 299NewFile (const char *name) 300{ 301 Arg arg[2]; 302 char *n; 303 FILE *new_file; 304 Boolean seek = 0; 305 306 if (current_file) { 307 if (!strcmp (current_file_name, "-")) 308 ; 309 else if (current_file_name[0] == '|') 310 pclose (current_file); 311 else 312 fclose (current_file); 313 } 314 if (!strcmp (name, "-")) 315 new_file = stdin; 316 else if (name[0] == '|') 317 new_file = popen (name+1, "r"); 318 else { 319 new_file = fopen (name, "r"); 320 seek = 1; 321 } 322 if (!new_file) { 323 /* XXX display error message */ 324 return; 325 } 326 XtSetArg (arg[0], XtNfile, new_file); 327 XtSetArg (arg[1], XtNseek, seek); 328 XtSetValues (dvi, arg, 2); 329 if (hadFile || name[0] != '-' || name[1] != '\0') { 330 XtSetArg (arg[0], XtNtitle, name); 331 if (name[0] != '/' && (n = strrchr (name, '/'))) 332 n = n + 1; 333 else 334 n = (char *)name; 335 XtSetArg (arg[1], XtNiconName, n); 336 XtSetValues (toplevel, arg, 2); 337 } 338 hadFile = 1; 339 SelectPageNumber ("1"); 340 strcpy (current_file_name, name); 341 current_file = new_file; 342} 343 344static char fileBuf[1024]; 345 346static void 347ResetMenuEntry (Widget entry) 348{ 349 Arg arg[1]; 350 351 XtSetArg (arg[0], (String)XtNpopupOnEntry, entry); 352 XtSetValues (XtParent(entry) , arg, (Cardinal) 1); 353} 354 355/*ARGSUSED*/ 356 357static void 358NextPage (Widget entry, XtPointer name, XtPointer data) 359{ 360 name = name; /* unused; suppress compiler warning */ 361 data = data; 362 363 NextPageAction((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0); 364 ResetMenuEntry (entry); 365} 366 367static void 368NextPageAction (Widget widget, XEvent *event, 369 String *params, Cardinal *num_params) 370{ 371 Arg args[1]; 372 int number; 373 374 XtSetArg (args[0], XtNpageNumber, &number); 375 XtGetValues (dvi, args, 1); 376 SetPageNumber (number+1); 377 378 widget = widget; /* unused; suppress compiler warning */ 379 event = event; 380 params = params; 381 num_params = num_params; 382} 383 384/*ARGSUSED*/ 385 386static void 387PreviousPage (Widget entry, XtPointer name, XtPointer data) 388{ 389 name = name; /* unused; suppress compiler warning */ 390 data = data; 391 392 PreviousPageAction ((Widget)NULL, (XEvent *) 0, (String *) 0, 393 (Cardinal *) 0); 394 ResetMenuEntry (entry); 395} 396 397static void 398PreviousPageAction (Widget widget, XEvent *event, 399 String *params, Cardinal *num_params) 400{ 401 Arg args[1]; 402 int number; 403 404 XtSetArg (args[0], XtNpageNumber, &number); 405 XtGetValues (dvi, args, 1); 406 SetPageNumber (number-1); 407 408 widget = widget; /* unused; suppress compiler warning */ 409 event = event; 410 params = params; 411 num_params = num_params; 412} 413 414/* ARGSUSED */ 415 416static void 417SelectPage (Widget entry, XtPointer name, XtPointer data) 418{ 419 name = name; /* unused; suppress compiler warning */ 420 data = data; 421 422 SelectPageAction ((Widget)NULL, (XEvent *) 0, (String *) 0, 423 (Cardinal *) 0); 424 ResetMenuEntry (entry); 425} 426 427static void 428SelectPageAction (Widget widget, XEvent *event, 429 String *params, Cardinal *num_params) 430{ 431 widget = widget; /* unused; suppress compiler warning */ 432 event = event; 433 params = params; 434 num_params = num_params; 435 436 MakePrompt (toplevel, "Page number", SelectPageNumber, ""); 437} 438 439 440static void 441DoPrint (const char *name) 442{ 443 FILE *print_file; 444 RETSIGTYPE (*handler)(int); 445 446 /* Avoid dieing because of an invalid command. */ 447 handler = signal(SIGPIPE, SIG_IGN); 448 449 print_file = popen(name, "w"); 450 if (!print_file) 451 /* XXX print error message */ 452 return; 453 DviSaveToFile(dvi, print_file); 454 pclose(print_file); 455 signal(SIGPIPE, handler); 456 strcpy(current_print_command, name); 457} 458 459static void 460RerasterizeAction (Widget widget, XEvent *event, 461 String *params, Cardinal *num_params) 462{ 463 Arg args[1]; 464 int number; 465 466 if (current_file_name[0] == 0) { 467 /* XXX display an error message */ 468 return; 469 } 470 XtSetArg (args[0], XtNpageNumber, &number); 471 XtGetValues (dvi, args, 1); 472 NewFile(current_file_name); 473 SetPageNumber (number); 474 475 widget = widget; /* unused; suppress compiler warning */ 476 event = event; 477 params = params; 478 num_params = num_params; 479} 480 481/* ARGSUSED */ 482 483static void 484Print (Widget entry, XtPointer name, XtPointer data) 485{ 486 name = name; /* unused; suppress compiler warning */ 487 data = data; 488 489 PrintAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0); 490 ResetMenuEntry (entry); 491} 492 493static void 494PrintAction (Widget widget, XEvent *event, 495 String *params, Cardinal *num_params) 496{ 497 widget = widget; /* unused; suppress compiler warning */ 498 event = event; 499 params = params; 500 num_params = num_params; 501 502 if (current_print_command[0]) 503 strcpy (fileBuf, current_print_command); 504 else 505 fileBuf[0] = '\0'; 506 MakePrompt (toplevel, "Print command:", DoPrint, fileBuf); 507} 508 509 510/* ARGSUSED */ 511 512static void 513OpenFile (Widget entry, XtPointer name, XtPointer data) 514{ 515 name = name; /* unused; suppress compiler warning */ 516 data = data; 517 518 OpenFileAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0); 519 ResetMenuEntry (entry); 520} 521 522static void 523OpenFileAction (Widget widget, XEvent *event, 524 String *params, Cardinal *num_params) 525{ 526 widget = widget; /* unused; suppress compiler warning */ 527 event = event; 528 params = params; 529 num_params = num_params; 530 531 if (current_file_name[0]) 532 strcpy (fileBuf, current_file_name); 533 else 534 fileBuf[0] = '\0'; 535 MakePrompt (toplevel, "File to open:", NewFile, fileBuf); 536} 537 538/* ARGSUSED */ 539 540static void 541Quit (Widget entry, XtPointer closure, XtPointer data) 542{ 543 entry = entry; /* unused; suppress compiler warning */ 544 closure = closure; 545 data = data; 546 547 QuitAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0); 548} 549 550static void 551QuitAction (Widget widget, XEvent *event, 552 String *params, Cardinal *num_params) 553{ 554 widget = widget; /* unused; suppress compiler warning */ 555 event = event; 556 params = params; 557 num_params = num_params; 558 559 exit (0); 560} 561 562Widget promptShell, promptDialog; 563MakePromptFunc promptfunction; 564 565/* ARGSUSED */ 566static 567void CancelAction (Widget widget, XEvent *event, 568 String *params, Cardinal *num_params) 569{ 570 widget = widget; /* unused; suppress compiler warning */ 571 event = event; 572 params = params; 573 num_params = num_params; 574 575 if (promptShell) { 576 XtSetKeyboardFocus(toplevel, (Widget) None); 577 XtDestroyWidget(promptShell); 578 promptShell = (Widget) 0; 579 } 580} 581 582static 583void AcceptAction (Widget widget, XEvent *event, 584 String *params, Cardinal *num_params) 585{ 586 (*promptfunction)(XawDialogGetValueString(promptDialog)); 587 CancelAction (widget, event, params, num_params); 588} 589 590static void 591MakePrompt(Widget centerw, const char *prompt, 592 MakePromptFunc func, const char *def) 593{ 594 static Arg dialogArgs[] = { 595 {XtNlabel, 0}, 596 {XtNvalue, 0}, 597 }; 598 Arg valueArgs[1]; 599 Arg centerArgs[2]; 600 Position source_x, source_y; 601 Position dest_x, dest_y; 602 Dimension center_width, center_height; 603 Dimension prompt_width, prompt_height; 604 Widget valueWidget; 605 606 CancelAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0); 607 promptShell = XtCreatePopupShell ("promptShell", transientShellWidgetClass, 608 toplevel, NULL, (Cardinal) 0); 609 dialogArgs[0].value = (XtArgVal)prompt; 610 dialogArgs[1].value = (XtArgVal)def; 611 promptDialog = XtCreateManagedWidget( "promptDialog", dialogWidgetClass, 612 promptShell, dialogArgs, XtNumber (dialogArgs)); 613 XawDialogAddButton(promptDialog, "accept", NULL, (XtPointer) 0); 614 XawDialogAddButton(promptDialog, "cancel", NULL, (XtPointer) 0); 615 valueWidget = XtNameToWidget (promptDialog, "value"); 616 if (valueWidget) { 617 XtSetArg (valueArgs[0], (String)XtNresizable, TRUE); 618 XtSetValues (valueWidget, valueArgs, 1); 619 /* 620 * as resizable isn't set until just above, the 621 * default value will be displayed incorrectly. 622 * rectify the situation by resetting the values 623 */ 624 XtSetValues (promptDialog, dialogArgs, XtNumber (dialogArgs)); 625 } 626 XtSetKeyboardFocus (promptDialog, valueWidget); 627 XtSetKeyboardFocus (toplevel, valueWidget); 628 XtRealizeWidget (promptShell); 629 /* 630 * place the widget in the center of the "parent" 631 */ 632 XtSetArg (centerArgs[0], XtNwidth, ¢er_width); 633 XtSetArg (centerArgs[1], XtNheight, ¢er_height); 634 XtGetValues (centerw, centerArgs, 2); 635 XtSetArg (centerArgs[0], XtNwidth, &prompt_width); 636 XtSetArg (centerArgs[1], XtNheight, &prompt_height); 637 XtGetValues (promptShell, centerArgs, 2); 638 source_x = (center_width - prompt_width) / 2; 639 source_y = (center_height - prompt_height) / 3; 640 XtTranslateCoords (centerw, source_x, source_y, &dest_x, &dest_y); 641 XtSetArg (centerArgs[0], XtNx, dest_x); 642 XtSetArg (centerArgs[1], XtNy, dest_y); 643 XtSetValues (promptShell, centerArgs, 2); 644 XtMapWidget(promptShell); 645 promptfunction = func; 646} 647 648/* 649Local Variables: 650c-indent-level: 4 651c-continued-statement-offset: 4 652c-brace-offset: -4 653c-argdecl-indent: 4 654c-label-offset: -4 655c-tab-always-indent: nil 656End: 657*/ 658